python noobie范围问题

ama*_*awa 8 python scoping

我写了这段代码:

x = 0
def counter():
 x = 1
 def temp(self):
  print x
  x += 1
 return temp
Run Code Online (Sandbox Code Playgroud)

试图测试python是词法还是动态范围.我的想法是这样的

y = counter()
y()
Run Code Online (Sandbox Code Playgroud)

应该打印0或1,这将告诉我python如何作用域.但是,调用y会抛出一个异常,说x未定义.在理解Python如何工作的过程中,似乎存在一些根本性的缺陷.

谁能解释一下这是如何工作的?是的,我知道可以使用对象轻松完成.我正试图探索在不使用对象的情况下给出函数状态的想法.我用这种方式编写代码是因为上面翻译成像SCI这样的词汇范围的语言肯定会有效.

unu*_*tbu 10

来自文档:

Python的一个特殊之处在于 - 如果没有全局语句生效 - 对名称的赋值总是进入最内层范围.分配不复制数据 - 它们只是将名称绑定到对象.

所以,当Python解析时

 def temp(self):
  print x
  x += 1
Run Code Online (Sandbox Code Playgroud)

它看到了分配x += 1,因此决定x必须在最里面的范围内.稍后你调用temp(...)via y()- (顺便说一句,要么self应该从定义中省略,temp否则y()应该提供一个参数) - Python遇到print x语句并发现x尚未在本地(最里面)范围内定义.因此错误,

UnboundLocalError: local variable 'x' referenced before assignment
Run Code Online (Sandbox Code Playgroud)

如果你宣布

 def temp(self):
     global x
Run Code Online (Sandbox Code Playgroud)

那么Python将x在全局范围内寻找(在哪里x=0).在Python2中,没有办法告诉Python x在扩展范围内寻找(在哪里x=1).但是在Python3中可以通过声明来实现

 def temp(self):
     nonlocal x
Run Code Online (Sandbox Code Playgroud)


Tho*_*ers 6

Python有两个范围(实际上是三个)以及嵌套本地范围的特殊规则.这两个范围对于模块级名称是全局的,对于函数中的任何内容都是本地的.您在函数中分配的任何内容都是自动本地的,除非您使用该函数中global语句声明它.如果使用未分配给函数中任何位置的名称,则它不是本地名称; Python将(词法)搜索嵌套函数,以查看它们是否具有该名称作为本地名称.如果没有嵌套函数或者其中任何一个名称不是本地函数,则假定该名称是全局的.

(全局命名空间也很特殊,因为它实际上是模块全局命名空间和内置命名空间,它隐藏在builtins__builtins__模块中.)

在您的情况下,您有三个 x变量:一个在模块(全局)范围中,一个在counter函数中,一个在temp函数中 - 因为+=它也是赋值语句.因为分配给名称的这一事实使其成为函数的本地,所以您的+=语句将尝试使用尚未分配的局部变量,这将引发UnboundLocalError.

如果您希望所有这三个x引用都引用全局变量,则需要global x同时执行counter和该temp函数.在Python 3.x(但不是2.x)中,有一个nonlocal声明非常类似于global你可以用来为temp变量赋值counter,但是让全局x单独使用.


AHM*_*AHM 2

Python 中的闭包是不可写的,因此您不能以这种方式编写代码。如果您只读取函数内部的变量,那么应该没问题。在 Python 3 中,您可以使用nonlocal关键字来获得您想要的行为。

如果您使用的是Python 2.5或更高版本,您还可以使用yield关键字将上述代码编写为生成器。