3

我注意到 python 不允许您在类定义中将类的实例作为静态成员添加到自身。

>>> class Foo:
...     A = Foo()
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in Foo
NameError: name 'Foo' is not defined

但是,以下任一工作:

>>> class Foo:
...     pass
... 
>>> class Foo:
...     A = Foo()
... 
>>> Foo.A
<__main__.Foo instance at 0x100854440>

或者

>>> class Foo:
...     pass
... 
>>> Foo.A = Foo()
>>> 
>>> Foo.A
<__main__.Foo instance at 0x105843440>

我找不到任何有启发性的代码示例或解释。为什么python对第一种情况的处理方式不同?在随后的两个案例中,A 将走向何方?

4

4 回答 4

6

您的第一个示例不起作用,因为您尚未创建该类Foo。您正在这样做(因此NameError

您的第二个示例有效,因为您有一个名为Foo(). 你覆盖它,但你仍然保留它的副本。看看这个:

>>> class Foo:
...     def __init__(self):
...             print 'hi'
... 
>>> class Foo:
...     A = Foo()
... 
hi
>>> Foo.A
<__main__.Foo instance at 0x101019950>
>>> Foo.A.__init__
<bound method Foo.__init__ of <__main__.Foo instance at 0x101019950>>

A是具有您覆盖的类的值的属性。

至于您的第三个示例,您只是在创建一个作为该类实例的类的属性。

于 2013-08-21T06:58:54.163 回答
3

编辑:查看这个问题以获取 Python 中自引用类的示例。)

我认为这将说明:

>>> class Test:
...     a = 3
...
>>> class Test:
...     m = Test()
...
>>>
>>> t = Test()
>>> t.m
<__main__.Test object at 0x01E73690>
>>> t.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute 'a'
>>> t.m.a
3

令人惊讶的是,这为您提供了两个具有相同名称的不同类。但我猜第一堂课“迷路了”,只能通过第二堂课进入。

于 2013-08-21T06:58:42.127 回答
1

创建一个类首先要评估它的主体,然后在最后创建一个类对象。

所以

class Foo:
    A = Foo() # here class Foo doesn't exist yet
# but here it exists.

是创建类对象的工作原理。)

您的第二个示例创建一个类,然后创建另一个具有相同名称的类,与第一个类没有任何关系。因此,

>>> isinstance(Foo.A, Foo)
False

您的第三个示例在创建后使用该类来扩展它。

所以,

>>> isinstance(Foo.A, Foo)
True

为什么python对第一种情况的处理方式不同?

因为标识符还不存在。

在随后的两个案例中,A 将走向何方?

这是什么意思,它要去哪里?

于 2013-08-21T07:39:58.790 回答
0

在类定义时,类本身还不存在,缩进块的内容被执行,任何名称都被解析并调用函数。此时,类的名称、基类和包含要存储在类中的名称和值的字典被传递给创建实际类并将其绑定到指定名称的元类。您可以在类初始化时通过使用metaclass. 这将执行类定义中的代码,将名称、基数和字典传递给元类函数,该函数创建类并在其中创建类的实例,然后将其绑定到名称。考虑:

def staticInstanceMetaclass(name, bases, dict_):
    ret=type(name, bases, dict_)
    for i in dict_:
      if dict_[i]=='STATICINSTANCE':
        setattr(ret,i,ret())
    return ret

class ClassWithStaticInstance(object):
    __metaclass__=staticInstanceMetaclass
    myStaticInstance='STATICINSTANCE'
    myFirstVar=5

print ClassWithStaticInstance.myStaticInstance

请注意,在上面的示例中,dict_包含

{'myStaticInstance': 'STATICINSTANCE', '__module__': '__main__', '__metaclass__': <function staticInstanceMetaclass at 0x1213668>, 'myFirstVar': 5}

这与在 python 中预先创建静态实例差不多。有关元类以及如何影响类创建的更多信息,请参阅问题。

于 2013-08-21T09:27:59.657 回答