2013-05-29 3 views
1

Раньше я обсуждал некоторые вопросы, связанные с Python, и наткнулся на страницу this. Автор делает что-то вроде следующего:Почему переменные 'declare' в Python?

class TestClass(object): 
    first = str() 
    def __init__(self): 
     self.first = "Hello" 

Что такое точка «объявить» переменную first, как это? Я никогда не видел этого раньше, и я не могу, чтобы жизнь меня задумала о ситуации, когда полезно создать переменную, прежде чем присвоить ей какую-то ценность.

Приведенный выше пример может точно также выглядит следующим образом:

class TestClass(object): 
    def __init__(self, first="Hello"): 
     self.first = first 

... или я что-то отсутствует?

+0

Пример может иметь, но результаты не являются * точно * одинаковыми. – Elazar

+0

«first = str()» создает переменную, связанную с ** классом **, в то время как «self.first = ...» создает новую для экземпляра (это не значит, что это имеет смысл). –

+1

Просто помните: там, наверное, более ужасный * плохой код, чем хороший. – Voo

ответ

3

Это не объявление, это назначение ... переменной внутри класса, в отличие от переменной внутри экземпляра.

Рассмотрим следующий вывод:

>>> class K1(object): 
...  def __init__(self): 
...   self.attr = 'value' 
... 
>>> x = K1() 
>>> x.__dict__ 
{'attr': 'value'} 
>>> class K2(object): 
...  attr = 'value' 
...  def __init__(self): 
...   self.another = 'value2' 
... 
>>> y = K2() 
>>> y.__dict__ 
{'another': 'value2'} 

Здесь x является экземпляром класса K1 и имеет атрибут с именем attr и y является экземпляром класса К2 и имеет другой атрибут с именем another. Но:

>>> y.attr 
'value' 

Откуда это взялось? Он пришел из класса:

>>> y.__class__.__dict__ 
dict_proxy({'__module__': '__main__', 'attr': 'value', 
'__dict__': <attribute '__dict__' of 'K2' objects>, 
'__weakref__': <attribute '__weakref__' of 'K2' objects>, 
'__doc__': None, '__init__': <function __init__ at 0x80185b9b0>}) 

Это своего рода грязный, но вы можете увидеть attr сидит там. Если вы посмотрите на x.__class__.__dict__ нет attr:

>>> x.__class__.__dict__ 
dict_proxy({'__dict__': <attribute '__dict__' of 'K1' objects>, 
'__module__': '__main__', 
'__weakref__': <attribute '__weakref__' of 'K1' objects>, 
'__doc__': None, '__init__': <function __init__ at 0x80185b938>}) 

Когда вы получаете атрибут экземпляра, как x.attr или y.attr, Python сначала ищет что-то прилагается к самому экземпляру. Однако если ничего не найдено, оно «смотрит вверх», чтобы увидеть, определяет ли что-то другое этот атрибут. Для классов с наследованием, которые включают в себя список «порядок принятия решений». В этом случае нет наследования, о которых нужно беспокоиться, но следующим шагом является просмотр самого класса. Здесь, в K2, есть атрибут в классе с именем attr, так это то, что производит y.attr.

Вы можете изменить атрибут класса, чтобы изменить то, что отображается в y.attr:

>>> K2.attr = 'newvalue' 
>>> y.attr 
'newvalue' 

И в самом деле, если вы сделаете еще один экземпляр K2(), это тоже подберут новое значение:

>>> z = K2() 
>>> z.attr 
'newvalue' 

Обратите внимание, что при изменении х-х attr не влияет на новые экземпляры K1():

>>> w = K1() 
>>> w.attr = 'private to w' 
>>> w.attr 
'private to w' 
>>> x.attr 
'value' 

Это потому, что w.attr действительно w.__dict__['attr'], и x.attr действительно x.__dict__['attr']. С другой стороны, y.attr и z.attr оба действительно y.__class__.__dict__['attr'] и z.__class__.__dict__['attr'], а так как y.__class__ и z.__class__ оба являются K2, меняется K2.attr меняется оба.

(Я не уверен, что парень, который написал страницу, указанную в исходном вопросе, все это понимает. Создание атрибута на уровне класса, а затем создание одноуровневого уровня с одним и тем же именем является беспредметным.)

+0

Очень тщательный ответ, и я принимаю его. Похоже, что консенсус автора этого сообщения действительно не знал, что он делает ... – henrebotha

6

Тот факт, что автор использует

first = str() 

в отличие от

first = '' 

показывает, наряду с установкой self.first в __init__ все равно, что там нет никакого смысла в этом.

Может быть, автор путается и считает питон переменной необходимости быть объявлено первым -_- (очевидно при просмотре ссылки)

3

str() равно ""

>>> str() 
'' 

Я думаю, что автор хочет показать, что атрибуты экземпляра переопределяют атрибуты класса с одинаковым именем. Так что на выполнение

test = testclass() 
print test.__dict__ 

вы получите:

{'second': 'weird', 'third': 'test', 'first': 'Some'} 

не

{'second': '', 'third': '', 'first': ''}

но

print testclass.__dict__ 

напечатает атрибутов класса:

{'__module__': '__main__', 'third': '', 'second': '', '__doc__': None, '__init__': <function __init__ at 0xb5fed6bc>, 'first': ''} 
+1

простая путаница все еще звучит скорее :) – Elazar

+3

Я серьезно сомневаюсь, что это было намерение автора. – martineau

1

Существует действительно небольшая разница между этими двумя примерами:

class TestClass(object): 
    first = 'foo' 
    def __init__(self): 
     self.first = "Hello" 

print(TestClass.first) 

Выход:

foo 

Однако с:

class TestClass(object): 
    def __init__(self, first="Hello"): 
     self.first = "Hello" 

print(TestClass.first) 

Выход:

Traceback (most recent call last): 
    File "C:\Users\...\Desktop\test.py", line 5, in <module> 
    print(TestClass.first) 
AttributeError: type object 'TestClass' has no attribute 'first' 

Примечание: Но это не значит, что авторский код имеет смысл.Просто хотел указать на разницу.

+0

Моя ошибка.Спасибо :) – henrebotha

+0

@henrebotha: Рад я мог помочь :) –

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