2011-03-06 25 views
3

我让我的头周围的Python是第一次,我被困在这里: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' 

而且问题:

  • 什么是我h大约不知道__init__

我不认为这是一样的forward declaration,因此我希望这个问题不是重复的。

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

回答

6

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

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

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

+0

什么是麻烦? :) – senderle

+2

这是一个字符串输入非常快。 – Dimitry

+1

确实:) - +1的方式。 – senderle

1

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

一般来说,前向声明在Python中不是问题,因为只有在调用必要的函数时才会对引用进行评估。这里的问题是在定义时间处执行的类定义是。更,具体而言,这里是在Python解释器满足class声明会发生什么:

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

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

此问题也会在函数定义中弹出:当你做

def foo(x=bar()): pass 

然后bar会被调用一次,当时foo定义,永不再。


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

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

a = A() 

def foo(): 
    pass 
+0

代码无法运行:'NameError:全局名称'foo'未定义。但我明白你的意思。 – lorenzog

+0

@lorenzog:是的,这就是要点:如果你真的尝试初始化类,那么同样的事情会发生在上面,因为那时你正在查找一个尚未定义的名字。 – katrielalex

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

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

一个是一个实例属性 - 每一个都有自己的一个变量,和Foo(“BAA”)仅在创建A对象时才被评估。

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

在一般情况下,你可以,只要他们得到定义为其中尚不存在函数和类引用您评估前的基准(即之前你真正尝试调用该函数)。