Python内部函数的前向声明

时间:2011-03-06 20:27:40

标签: python class-design forward-declaration

我第一次看到Python,我被困在这里:

class A:
    def __init__(self):
        a = foo("baa")

class B(A):
    b = foo("boo")

def foo(string):
    return string

此时我加载了上面的文件(名为classes),发生了这种情况:

$ python
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from classes import *
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "classes.py", line 5, in <module>
    class B(A):
  File "classes.py", line 6, in B
    b = foo("boo")
NameError: name 'foo' is not defined

注意错误在B类中的情况,其中foo是直接调用而不是__init__。另请注意我尚未实例化类B

第一个问题:

  • 为什么会返回错误?我没有实例化课程。

继续前进。通过将foo()的定义移到上面几行来解决“问题”:

def foo(string):
    return string

class A:
    def __init__(self):
        a = foo("baa")

class B(A):
    b = foo("boo")

现在我可以做到

>>> x = B()
>>> x.b
'boo'

但我做不到

>>> y = A()
>>> y.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: A instance has no attribute 'a'

进一步的问题:

  • 我对__init__没有理解的是什么?

我不认为这与forward declaration相同,因此我希望这个问题不重复。

另一方面,我的目标是实现DSL,但这主要是让自己学习python的借口。

3 个答案:

答案 0 :(得分:6)

首先,在类B中,函数foo()在声明之前被调用。 A没有此问题,因为foo()仅在实例化类时调用 - 在定义函数foo之后。

对于你的第二个问题,y.a将无效,因为你没有说self.a = foo('stirng')a = foo('stirng')仅在__ init __范围内创建变量a。

理想的__ init __函数将变量分配给实例self

答案 1 :(得分:1)

你对__init__没有理解的事情是它只在你实例化(即创建一个)类A的实例时被调用。因为你的代码中没有任何地方你实际上创建了这个类的实例,所以你永远不会调用它的初始化器,因此永远不会遇到前向声明。

一般来说,前向声明在Python中不是问题,因为只有在调用必要的函数时才会计算引用。这里的问题是类定义是在define-time 执行的。更具体地说,这是Python解释器遇到class语句时发生的情况:

  • 它定义了一个新的命名空间(局部变量字典)来保存所有代码。
  • 它执行类定义中的代码。
  • 它将存储在本地名称空间中的任何内容放入类__dict__
  • 它关闭新命名空间并将新类添加到模块命名空间。

当然,你不需要知道定义一个类;你只需要记住,在第一次定义类时,将会执行类定义中的任何内容! (这很少是一个问题,因为类级变量首先不常见,通常不需要在定义时动态设置。)

这个问题也出现在函数定义中:当你做

def foo(x=bar()): pass

然后bar会在定义foo时调用一次,而不会再次调用。{/ p>


尝试运行以下代码,看看它是否澄清了事情:

class A():
    def __init__(self):
        self.a = foo()

a = A()

def foo():
    pass

答案 2 :(得分:1)

class A:
    def __init__(self):
        a = foo("baa")

class B(A):
    b = foo("boo")

a是一个实例属性 - 每个A都有自己的变量,只有在创建A对象时才会评估foo(“baa”)。

b是一个类属性 - 每个B对象共享b的相同副本,并且在定义类时评估foo(“boo”)。

一般情况下,只要在评估引用之前定义,就可以引用尚不存在的函数和类,即在您实际尝试之前调用函数。)