Различие между двумя типами определения свойств класса?
Есть ли разница между
class Foo(object):
bar = 1
def __init__(self):
... etc.
И
class Foo(object):
def __init__(self):
... etc.
Foo.bar = 1
В обоих случаях bar
является свойством класса, и оно одинаково для всех экземпляров класса, верно?
3 ответа:
Я бы сказал, что единственная разница заключается в том, что во втором случае
Foo.bar
не существует до тех пор, пока операторFoo.bar = 1
не будет выполнен, в то время как в первом случае он уже доступен при создании объекта класса.Это, вероятно, небольшая разница без какого-либо эффекта в вашем коде (если только нет кода, который требует
Foo.bar
, прежде чем он будет доступен во втором случае). Тем не менее, я бы сказал, что первый вариант лучше с точки зрения читаемости, так как вам не нужно прокручивать вниз, чтобы узнать атрибуты для вашего класса, они уже есть.
Если вы пишете свой собственный код, используйте:
class Foo(object): bar = 1
Потому что эта версия:
class Foo(object): pass Foo.bar = 1
Даже если это законно
- больше похоже на взлом.
- в большинстве случаев менее читаем.
У вас могут возникнуть проблемы, если вы попытаетесь получить доступ к атрибуту
bar
до его создания:>>> class Foo: ... pass ... >>> f = Foo() >>> f.bar Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Foo' object has no attribute 'bar' >>> Foo.bar = 1 >>> f.bar # but hey, now you're ok! 1
Кроме этого, я не вижу особых различий.
Обе версии одинаковы (см. расшифровку тестов в конце этого ответа), но обратите внимание, что (а) ни в том, ни в другом случае не является
bar
одинаковым для всех экземпляровFoo
.В момент создания экземпляра чтение
bar
на экземпляре будет считывать значение вFoo
, а присвоенияFoo.bar
будут отражаться в экземпляре до тех пор, покаinstance.bar
не будет присвоено.В этот момент присваивания экземпляр получает свою собственную запись__dict__
, которая полностью независима от класса.In [62]: class Foo: pass In [63]: Foo.bar = 1 In [64]: Foo.bar Out[64]: 1 In [65]: f = Foo() In [66]: f.bar Out[66]: 1 In [67]: f.bar +=1 In [68]: f.bar Out[68]: 2 In [69]: Foo.bar Out[69]: 1 In [70]: Foo.bar +=3 In [71]: Foo.bar Out[71]: 4 In [72]: g = Foo() In [73]: g.bar Out[73]: 4 In [74]: class Qux: bar = 1 In [75]: Qux.bar Out[75]: 1 In [76]: q = Qux() In [77]: q.bar Out[77]: 1 In [78]: q.bar+=1 In [79]: q.bar Out[79]: 2 In [80]: Qux.bar Out[80]: 1 In [81]: Qux.bar +=1 In [82]: r = Qux() In [83]: r.bar Out[83]: 2 In [84]: q.bar Out[84]: 2 In [85]: s = Qux() In [87]: s.__dict__ Out[87]: {} In [88]: q.__dict__ Out[88]: {'bar': 2} In [89]: Qux.bar = 'foo' In [90]: Qux.bar Out[90]: 'foo' In [91]: s.bar Out[91]: 'foo'