2013-08-21 4 views
2

Я заметил, что 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 относится к первому случаю по-другому? Где А происходит в каждом из двух последующих случаев?

ответ

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 является атрибутом, который имеет значение класса вы подчинившие.

Что касается вашего третьего примера, вы просто создаете атрибут класса, являющегося экземпляром класса.

3

(EDIT: смотреть на 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 

Удивительно, что дает два различных класса с тем же именем. Но я думаю, что первый класс «потерян» и доступен только через второй.

1

Создание класса работает, сначала оценивая его тело, а затем, в конце, создавая объект класса.

Так

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

(Here как создание объекта класса работ.)

Ваш второй пример создает класс, а затем создает еще один класс с тем же именем, не связанной с первой в так или иначе. Таким образом,

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

Ваш третий пример использует класс после его создания для его расширения.

Так,

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

Почему питон лечить первый случай по-другому?

Поскольку идентификатор еще не существует.

Куда А в каждом из двух последующих случаев?

Что это значит, где это происходит?

0

В момент определения класса сам класс еще не существует, содержимое отступающего блока выполняется и все имена разрешены и вызываются функции. В этот момент имя класса, базовые классы и словарь, содержащие имена и значения для хранения в классе, передаются в метакласс, который создает фактический класс и связывает его с указанным именем. Вы можете создать «статический» экземпляр класса во время инициализации класса с помощью metaclass. Это выполняет код внутри определения класса, передает имя, базы и 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} 

Это примерно так же близко, как вы получите заранее создавать статические экземпляры в питона. Для получения дополнительной информации о метаклассах и о том, как создать класс влияния, см. Вопрос this.

Смежные вопросы