python noobie范围界定问题
我写了这段代码:python noobie范围界定问题,python,scoping,Python,Scoping,我写了这段代码: x = 0 def counter(): x = 1 def temp(self): print x x += 1 return temp 尝试测试python是词法作用域还是动态作用域。我的想法是 y = counter() y() 应该打印0或1,这将告诉我python的作用域是如何划分的。但是,调用y会抛出一个异常,表示x未定义。在我对Python如何工作的理解中,似乎存在一些根本性的缺陷 有人能解释一下这是怎么回事吗?是的,我知道这可以通过使用对象轻松
x = 0
def counter():
x = 1
def temp(self):
print x
x += 1
return temp
尝试测试python是词法作用域还是动态作用域。我的想法是
y = counter()
y()
应该打印0或1,这将告诉我python的作用域是如何划分的。但是,调用y会抛出一个异常,表示x未定义。在我对Python如何工作的理解中,似乎存在一些根本性的缺陷
有人能解释一下这是怎么回事吗?是的,我知道这可以通过使用对象轻松完成。我试图探索在不使用对象的情况下赋予函数状态的想法。我以这种方式编写代码,因为将上述内容翻译成类似Scheme的词汇范围语言肯定会奏效 Python中的闭包是不可写的,因此不能用这种方式编写代码。如果您只从函数内部的变量读取,那么您应该很好。在Python3中,可以使用
非本地
关键字来获得所需的行为
如果您使用的是Python 2.5或更高版本,还可以使用yield关键字将上述代码作为生成器编写。来源:
Python的一个特殊怪癖是——如果
没有有效的全球声明——
给名字分配的任务总是在
最里面的范围。作业
不复制数据-它们只是绑定名称
对对象进行修改
因此,当Python解析时
def temp(self):
print x
x += 1
它看到赋值x+=1
,因此决定x
必须在最里面的范围内。当您稍后通过y()
调用temp(…)
时(顺便说一句,temp
的定义中应该省略self
,或者y()
应该提供一个参数)——Python遇到print x
语句,发现x
在本地(最里面的)范围。因此错误
UnboundLocalError: local variable 'x' referenced before assignment
如果你申报
def temp(self):
global x
然后Python将在全局范围内查找x
(其中x=0
)。
在Python2中,没有办法告诉Python在扩展范围(其中x=1
)中查找x
。但是在Python3中,这可以通过声明实现
def temp(self):
nonlocal x
Python有两个作用域(实际上是三个)加上嵌套局部作用域的特殊规则。这两个作用域是全局的,用于模块级名称,而局部的,用于函数中的任何内容。在函数中指定给的任何内容都自动是局部的,除非您在该函数中用global
语句声明它。如果您使用未指定给函数中任何位置的名称注意,它不是一个本地名称;Python将(从词汇上)搜索嵌套函数,以查看它们是否将该名称作为本地名称。如果没有嵌套函数或任何嵌套函数中的名称都不是本地名称,则假定该名称为全局名称
(全局名称空间也很特殊,因为它实际上是模块全局名称空间和内置名称空间,它们隐藏在内置
或\uuuuuuuuuuuu内置
模块中。)
在本例中,您有三个x
变量:一个在模块中(全局)作用域,一个在计数器
函数中,一个在临时
函数中——因为+=
也是一个赋值语句。因为赋值给名称的事实使其成为函数的局部变量,所以+=
语句将尝试使用尚未赋值的局部变量,这将引发一个错误n取消绑定LocalError
如果希望所有这三个
x
引用都引用全局变量,则需要在Python 3.x(而不是2.x)中的counter
和temp
函数中执行global x
,有一个类似于global
的nonlocal
声明,您可以使用它将temp
赋值给计数器中的变量,但不要使用全局x
。
总之,Python具有静态作用域规则。如果函数f定义或删除变量名,则变量名引用函数f闭包中的变量。如果函数f仅使用变量名(无定义或删除),则该名称引用该名称在f的父作用域中的任何含义。继续向上转到父作用域,直到找到定义或到达全局作用域。例如:
def f1(x):
def g(y):
z.foo = y # assigns global z
g(1)
def f2(x):
def g(y):
x.foo = y # assigns f2's variable, because f2 defines x
g(1)
def f3(x):
def g(y):
x = C()
x.foo = y # assigns g's variable, because g defines x
g(1)
全局
关键字和(在Python 3中)非局部
关键字覆盖默认范围规则
静态解析变量名时,动态解析变量值。变量值来自访问变量时该变量的最新定义或删除。值在变量所在的函数闭包中查找。感谢您的回复。以防万一不管怎样,我已经找到了解决这个问题的方法。我创建了一个“scoper”函数来建立一个计数器变量
>>> def gc():
... def scoper():
... scoper.s = 0
... def rtn():
... scoper.s += 1
... return scoper.s
... return rtn
... return scoper()
以上内容允许我这样做,它模仿了正确的闭包:
>>> a = gc()
>>> a()
1
>>> a()
2
>>> a()
3
>>> b = gc()
>>> b()
1
>>> a()
4
>>> b()
2
不管Python的人怎么称呼它,一个你忘记在Python函数中初始化的变量都有动态作用域。这是Python最明显的缺点之一(不一定是动态作用域,但有时是动态作用域)。@ChrisPacejo:“动态作用域”是什么意思(相对于词汇范围)?