什么是Python的方式有条件的阴影?

2024-04-26 04:47:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图基于一个条件重写一个函数,实际上只是有条件地隐藏一个变量。你知道吗

def a(b): #Line 1
  print "a",b
def c(b):
  if b is None:
    def a2(b):
      print 'local',b
    exec('a=a2')
  a(b) #Line 8
c(5)
c(None)
c(6) #line 11

显示打印

a 5
local None
a 6

如果我只是在c()中定义a(),那么它将始终在本地进行阴影处理,而不是做我想做的事情。如果我添加全局关键字,它不会做我想要的。我最终用exec命令实现了这一点,但我们都试图避免这种情况,只是感觉不太像python。你知道吗

所以我的问题是。如果不改变第1行、第2行或第8行,还有什么比这更像Python的方法呢?(我正在使用python2,但是如果答案是“只在python3中”,我会感兴趣)

在你问“为什么我不能换行1、2或8”之前,我不想做类似的事情

if b is None:
  def a2(b):
    print 'local',b
else:
  a2 = a
a2(b)

因为我需要把a的每个引用都改成a2,降低代码的可读性。你知道吗


Tags: 函数nonea2if定义islocaldef
3条回答

没有Pythonic方法可以做到这一点,因为您直接与Python LEGB变量模型作斗争。你知道吗

Python在编译时决定函数体中是否有覆盖全局变量的局部变量。所以你不能在运行时改变它。你知道吗

请注意,使用exec定义新局部变量的尝试似乎在一个实现的一个测试中起作用…但它并不总是在CPython 2.7或pypypy 2.7-2.5中起作用,而且它从不在CPython 3.4或Jython 2.5中起作用。你知道吗


我认为您甚至不需要这个,因为您可以创建一个名为a的本地,初始化为全局,然后覆盖它。或者,最好给它起一个不同的名字,这样读者就不那么困惑了:

def a(b): #Line 1
  print "a",b
def c(b):
  a2 = a
  if b is None:
    def a2(b):
      print 'local',b
  a2(b) #Line 8

你甚至可以通过使用一个参数来简化它(在这种情况下,你不必给它一个不同的名称…尽管就我个人而言,我仍然会这样做):

def c(b, a=a):
  if b is None:
    def a(b):
      print 'local',b
  a(b) #Line 8

如果你担心性能,我不会;快速本地存储和加载的成本与全局查找的成本相比是很小的,所以很少有明显的区别。事实上,从您对为什么不想更改第8行的描述来看,似乎您计划多次调用该函数。在这种情况下,一个全局加载、一个快速的本地存储和一大堆快速的本地加载将比一大堆全局加载快得多,因此您可以免费获得一个优化。但你可以随时测试和查看。你知道吗


如果您真的想拥有类似于本地名称空间但可操作的东西,那么显而易见的答案就是使用显式dict:

def a(b): #Line 1
  print "a",b
def c(b):
  n = globals().copy()
  if b is None:
    def a2(b):
      print 'local',b
    n['a'] = a2
  n['a'](b) #Line 8

如果太冗长,可以轻松地将dict包装为对象的__dict__,并使用n.a而不是n['a'],使用SimpleNamespace,或者:

class Namespace(object): pass
n = Namespace()
n.__dict__ = globals().copy()

或者您可以非常棘手地编写一个decorator,用自定义名称空间从代码对象中动态创建一个新的函数对象。但是,当它所做的只是让你的代码更难理解时,为什么要变得棘手呢?你知道吗

def c(b):
  if b is None:
    def a(b):
      print 'local',b
  else:
    a = globals()['a']
  a(b) #Line 8

问题是有时a是局部的,有时它应该是全局的。解决方法是通过使其成为函数参数来确保它始终是本地的,但是默认情况下,它引用的是它可能隐藏的函数。你知道吗

def a(b):
    print "a", b

def c(b, a=a):
    if b is None:
        def a(b):
            print 'local', b
    a(b)

相关问题 更多 >