Область видимости переменной класса для статических методов и методов класса - PullRequest
0 голосов
/ 15 января 2019

Я обнаружил странное поведение (по крайней мере, странное для меня) с переменными класса Python.

class Base(object):
    _var = 0

    @classmethod
    def inc_class(cls):
        cls._var += 1

    @staticmethod
    def inc_static():
        Base._var += 1

class A(Base):
    pass

class B(Base):
    pass

a = A()
b = B()

a.inc_class()
b.inc_class()
a.inc_static()
b.inc_static()

print(a._var)
print(b._var)
print(Base._var)

Вывод 1 1 2.

Это удивляет меня (я ожидал 4 4 4), и мне интересно, почему?

Ответы [ 2 ]

0 голосов
/ 15 января 2019

Хотя эти два класса наследуются от базового класса, они являются совершенно разными объектами. Благодаря реализации a и b у вас есть два объекта, которые принадлежат двум отдельным классам. Когда вы звоните

a.inc_class()
b.inc_class()

Вы увеличиваете атрибут _var класса A один раз, а затем делаете то же самое для класса B. Даже если они имеют одно и то же имя, они являются разными объектами. Если у вас есть второй экземпляр класса A, скажем, a2, и вы вызовете функцию еще раз, тогда оба вызова будут манипулировать одной и той же переменной. Это объясняет, как вы получаете ваши первые два выхода.

Третий вывод относится к объекту базового класса. Опять же, даже если это одно и то же имя, это другой объект. Вы увеличиваете третий объект дважды, поэтому в качестве ответа вы получаете 2.

0 голосов
/ 15 января 2019

Когда украшено @classmethod, первый аргумент cls до inc_class(cls), ну, в общем, класс. <class '__main__.A'> и <class '__main__.B'> соответственно для A и B. Таким образом, cls._var относится к A _var, и аналогично для B. В inc_static, украшенном @staticmethod, аргумент отсутствует, вы явно ссылаетесь на <class '__main__.Base'>, другой _var.

Обратите внимание на атрибут '_var': 0 в Base и A в __dict__. @classmethod делает то, что вы ожидаете, привязывая членов к классам, в данном случае A и B.

>>> Base.__dict__
mappingproxy({'__module__': '__main__', '_var': 0, 'inc_class': <classmethod 
object at 0x7f23037a8b38>, 'inc_static': <staticmethod object at 
0x7f23037a8c18>, '__dict__': <attribute '__dict__' of 'Base' objects>, 
'__weakref__': <attribute '__weakref__' of 'Base' objects>, '__doc__': None})

>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None})`

После звонка Base.inc_static():

>>> Base.__dict__
mappingproxy({'__module__': '__main__', '_var': 1, 'inc_class': 
<classmethod object at 0x7f23037a8b38>, 'inc_static': <staticmethod 
object at 0x7f23037a8c18>, '__dict__': <attribute '__dict__' of 'Base' 
objects>, '__weakref__': <attribute '__weakref__' of 'Base' objects>, 
'__doc__': None})

>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None})

После звонка A.inc_class():

>>> Base.__dict__
mappingproxy({'__module__': '__main__', '_var': 1, 'inc_class': 
<classmethod object at 0x7f23037a8b38>, 'inc_static': <staticmethod 
object at 0x7f23037a8c18>, '__dict__': <attribute '__dict__' of 'Base' 
objects>, '__weakref__': <attribute '__weakref__' of 'Base' objects>, 
'__doc__': None})

>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None, '_var': 1})

Интересно то, как инициализируется A 1038 *. Обратите внимание, что вы делаете cls._var += 1 до того, как cls._var было определено. Как объяснено здесь , cls._var += 1 эквивалентно cls._var = cls._var; cls._var += 1. Из-за способа , в котором Python выполняет поиск , первое чтение cls._var завершится неудачей в A и продолжит находить его в Base. При присвоении _var добавляется A __dict__ со значением Base._var, и тогда все в порядке.

>>> class Base(object):
...     _var = 10
...     @classmethod
...     def inc_class(cls):
...         cls._var += 1
... 
>>> class A(Base):
...     pass
... 
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None})
>>> A.inc_class()
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None, '_var': 11})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...