python自己类型的静态字段

时间:2013-08-21 06:53:48

标签: python

我注意到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 个答案:

答案 0 :(得分: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是一个属性,它具有您覆盖的类的值。

至于你的第三个例子,你只是创建一个类的属性,它是一个类的实例。

答案 1 :(得分:3)

编辑:请查看this question以获取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

令人惊讶的是,它为您提供了两个具有相同名称的不同类。但我猜第一堂课“丢失了”,只能通过第二堂课获得。

答案 2 :(得分:1)

创建一个类的工作原理是首先评估它的主体,然后最后创建一个类对象。

所以

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

Here是创建类对象的方式。)

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

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

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

所以,

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

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

因为标识符尚不存在。

  

在后两个案例中,每个案件的A在哪里?

这是什么意思,它在哪里?

答案 3 :(得分:0)

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

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中预先创建静态实例一样接近。有关元类的更多信息以及影响类的创建方式,请参阅this问题。