Python 在函数中创建类并访问包含函数中定义的函数';s范围

Python 在函数中创建类并访问包含函数中定义的函数';s范围,python,namespaces,scope,Python,Namespaces,Scope,编辑: 请看我在这个问题底部的完整答案 tl;dr answer:Python具有静态嵌套的作用域。静态 方面可以和隐式变量声明交互,产生不明显的结果 (这可能特别令人惊讶,因为这种语言通常是动态的) 我原以为我能很好地处理Python的作用域规则,但这个问题让我彻底陷入困境,我的google fu让我失望(我并不感到惊讶——看看问题标题;) 我将从一些预期效果的示例开始,但请随意跳到示例4以了解有趣的部分 示例1。 >>> x = 3 >>> class M

编辑

请看我在这个问题底部的完整答案

tl;dr answer:Python具有静态嵌套的作用域。静态 方面可以和隐式变量声明交互,产生不明显的结果

(这可能特别令人惊讶,因为这种语言通常是动态的)

我原以为我能很好地处理Python的作用域规则,但这个问题让我彻底陷入困境,我的google fu让我失望(我并不感到惊讶——看看问题标题;)

我将从一些预期效果的示例开始,但请随意跳到示例4以了解有趣的部分

示例1。

>>> x = 3
>>> class MyClass(object):
...     x = x
... 
>>> MyClass.x
3
>>> def mymethod(self):
...     return self.x
... 
>>> x = 3
>>> class MyClass(object):
...     x = x
...     mymethod = mymethod
...
>>> MyClass().mymethod()
3
>>> def myfunc():
...     x = 3
...     class MyClass(object):
...         x = x
...     return MyClass
... 
>>> myfunc().x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in myfunc
  File "<stdin>", line 4, in MyClass
NameError: name 'x' is not defined
>>> def my_defining_func():
...     def mymethod(self):
...         return self.y
...     class MyClass(object):
...         mymethod = mymethod
...         y = 3
...     return MyClass
... 
>>> my_defining_func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in my_defining_func
  File "<stdin>", line 5, in MyClass
NameError: name 'mymethod' is not defined
>>> def fun1():
...     x = 3
...     def fun2():
...         print x
...     return fun2
... 
>>> fun1()()
3
非常简单:在类定义期间,我们能够访问外部(在本例中为全局)范围中定义的变量

示例2。

>>> x = 3
>>> class MyClass(object):
...     x = x
... 
>>> MyClass.x
3
>>> def mymethod(self):
...     return self.x
... 
>>> x = 3
>>> class MyClass(object):
...     x = x
...     mymethod = mymethod
...
>>> MyClass().mymethod()
3
>>> def myfunc():
...     x = 3
...     class MyClass(object):
...         x = x
...     return MyClass
... 
>>> myfunc().x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in myfunc
  File "<stdin>", line 4, in MyClass
NameError: name 'x' is not defined
>>> def my_defining_func():
...     def mymethod(self):
...         return self.y
...     class MyClass(object):
...         mymethod = mymethod
...         y = 3
...     return MyClass
... 
>>> my_defining_func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in my_defining_func
  File "<stdin>", line 5, in MyClass
NameError: name 'mymethod' is not defined
>>> def fun1():
...     x = 3
...     def fun2():
...         print x
...     return fun2
... 
>>> fun1()()
3
再次强调(暂时忽略为什么要这样做),这里没有什么意外:我们可以访问外部作用域中的函数

注意:正如弗里德里克在下面指出的,这个函数似乎不起作用。请参见示例5(及以上)

示例3。

>>> x = 3
>>> class MyClass(object):
...     x = x
... 
>>> MyClass.x
3
>>> def mymethod(self):
...     return self.x
... 
>>> x = 3
>>> class MyClass(object):
...     x = x
...     mymethod = mymethod
...
>>> MyClass().mymethod()
3
>>> def myfunc():
...     x = 3
...     class MyClass(object):
...         x = x
...     return MyClass
... 
>>> myfunc().x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in myfunc
  File "<stdin>", line 4, in MyClass
NameError: name 'x' is not defined
>>> def my_defining_func():
...     def mymethod(self):
...         return self.y
...     class MyClass(object):
...         mymethod = mymethod
...         y = 3
...     return MyClass
... 
>>> my_defining_func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in my_defining_func
  File "<stdin>", line 5, in MyClass
NameError: name 'mymethod' is not defined
>>> def fun1():
...     x = 3
...     def fun2():
...         print x
...     return fun2
... 
>>> fun1()()
3
嗯…打扰一下

这与示例2有什么不同

我完全糊涂了。请帮我整理一下。 谢谢

顺便说一下,这可能不仅仅是我理解上的问题,我已经在Python2.5.2和Python2.6.2上试过了。不幸的是,目前我只能接触到这些,但它们都表现出相同的行为

编辑 根据:在执行过程中的任何时候,至少有三个嵌套作用域的名称空间可以直接访问:

  • 最内部的作用域,即 首先搜索,包含本地 名字
  • 任何封闭函数的作用域 已搜索的函数 从最近的封闭 范围,包含非本地,但也包含 非全局名称
  • 倒数第二个作用域包含 当前模块的全局名称
  • 最外层范围(最后搜索) 名称空间包含内置的 名字
#四,。似乎是第二个例子的反例

编辑2

示例5.

>>> x = 3
>>> class MyClass(object):
...     x = x
... 
>>> MyClass.x
3
>>> def mymethod(self):
...     return self.x
... 
>>> x = 3
>>> class MyClass(object):
...     x = x
...     mymethod = mymethod
...
>>> MyClass().mymethod()
3
>>> def myfunc():
...     x = 3
...     class MyClass(object):
...         x = x
...     return MyClass
... 
>>> myfunc().x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in myfunc
  File "<stdin>", line 4, in MyClass
NameError: name 'x' is not defined
>>> def my_defining_func():
...     def mymethod(self):
...         return self.y
...     class MyClass(object):
...         mymethod = mymethod
...         y = 3
...     return MyClass
... 
>>> my_defining_func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in my_defining_func
  File "<stdin>", line 5, in MyClass
NameError: name 'mymethod' is not defined
>>> def fun1():
...     x = 3
...     def fun2():
...         print x
...     return fun2
... 
>>> fun1()()
3
编辑3

正如@Frédéric所指出的,将的赋值给一个与外部作用域同名的变量似乎“掩盖”了外部变量,从而阻止了赋值的运行

因此,示例4的这个修改版本可以工作:

def my_defining_func():
    def mymethod_outer(self):
        return self.y
    class MyClass(object):
        mymethod = mymethod_outer
        y = 3
    return MyClass

my_defining_func()
但是,这并不是:

def my_defining_func():
    def mymethod(self):
        return self.y
    class MyClass(object):
        mymethod_temp = mymethod
        mymethod = mymethod_temp
        y = 3
    return MyClass

my_defining_func()
我仍然不完全理解为什么会发生这种掩蔽:当赋值发生时,名称绑定不应该发生吗

此示例至少提供了一些提示(以及更有用的错误消息):

对g()的调用将引用由for绑定到f()中的变量 环如果在执行循环之前调用g(),则会出现NameError 被抚养

让我们运行Tim示例的两个简单版本:

>>> i = 6
>>> def f(x):
...     def g():
...             print i
...     # ...
...     # later
...     # ...
...     i = x
...     g()
... 
>>> f(3)
3
g()
在其内部作用域中没有找到
i
时,它会动态地向外搜索,在
f
的作用域中找到
i
,该作用域已通过
i=x
赋值绑定到
3

但是更改
f
中最后两条语句的顺序会导致错误:

>>> i = 6
>>> def f(x):
...     def g():
...             print i
...     # ...
...     # later
...     # ...
...     g()
...     i = x  # Note: I've swapped places
... 
>>> f(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in f
  File "<stdin>", line 3, in g
NameError: free variable 'i' referenced before assignment in enclosing scope
因此,尽管C很乐意使用一个未绑定的变量(使用之前存储在那里的任何东西:在本例中为134520820),Python(谢天谢地)拒绝了


有趣的是,静态嵌套的作用域实现了“Python编译器所做的最重要的优化:函数的局部变量不保存在dict中,它们位于紧密的值向量中,每个局部变量访问都使用该向量中的索引,而不是名称查找。”

这是Python名称解析规则的产物:您只能访问全局范围和局部范围,但不能访问介于两者之间的范围,例如,不能访问直接外部范围

EDIT:上述内容措词不当,您确实可以访问外部作用域中定义的变量,但通过从非全局命名空间执行
x=x
mymethod=mymethod
操作,您实际上是在用本地定义的变量屏蔽外部变量

在示例2中,您的直接外部作用域是全局作用域,因此
MyClass
可以看到
mymethod
,但在示例4中,您的直接外部作用域是
myu defining_func()
,因此它不能,因为
mymethod
的外部定义已经被其局部定义屏蔽

有关非本地名称解析的详细信息,请参阅

还请注意,出于上述原因,我无法让示例3在Python 2.6.5或3.1.2下运行:

>>> def myfunc():
...     x = 3
...     class MyClass(object):
...         x = x
...     return MyClass
... 
>>> myfunc().x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in myfunc
  File "<stdin>", line 4, in MyClass
NameError: name 'x' is not defined

这是Python名称解析规则的产物:您只能访问全局和局部作用域,但不能访问介于两者之间的作用域,例如,不能访问直接外部作用域

EDIT:上述内容措词不当,您确实可以访问外部作用域中定义的变量,但通过从非全局命名空间执行
x=x
mymethod=mymethod
操作,您实际上是在用本地定义的变量屏蔽外部变量

在示例2中,您的直接外部作用域是全局作用域,因此
MyClass
可以看到
mymethod
,但在示例4中,您的直接外部作用域是
myu defining_func()
,因此它不能,因为
mymethod
的外部定义已经被其局部定义屏蔽

有关非本地名称解析的详细信息,请参阅

还请注意,出于上述原因,我无法让示例3在Python 2.6.5或3.1.2下运行:

>>> def myfunc():
...     x = 3
...     class MyClass(object):
...         x = x
...     return MyClass
... 
>>> myfunc().x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in myfunc
  File "<stdin>", line 4, in MyClass
NameError: name 'x' is not defined

这篇文章已经有几年的历史了,但它属于