Доступ к dict наследуемых переменных класса в производном классе - PullRequest
0 голосов
/ 29 октября 2018

Предположим, у нас есть базовый класс A, который содержит некоторые переменные класса. Этот класс также имеет метод класса foo, который делает что-то с этими переменными. Поскольку это поведение не должно быть жестко запрограммировано (например, нам не нужно изменять foo при добавлении новых переменных класса), foo читает cls.__dict__ вместо прямой ссылки на переменные.
Теперь мы представляем производный класс: B расширяет A еще несколькими переменными класса, а также наследует foo. Пример кода:

class A:
  x = 0
  y = 1
  @classmethod
  def foo(cls):
    print([name for name, prop in cls.__dict__.items() if type(prop) is int])

class B(A):
  z = 3

print(B.x)  # prints "0"
A.foo()     # prints "['x', 'y']"
B.foo()     # prints "['z']" -- why not "['x', 'y', 'z']"?

Поэтому мой вопрос таков: почему B.__dict__ не содержит переменных, унаследованных от A, и если их там нет, то где они находятся?

Это не дубликат Доступ к атрибутам класса от родителей в методах экземпляра , потому что я не просто хочу запрашивать конкретные переменные, которые находятся в базовом классе - Я хочу перечислить их , не зная их имен. Ответы, относящиеся к MRO, приведенные в этом вопросе, также могут быть применимы и здесь, но первоначальная проблема, на мой взгляд, другая.

1 Ответ

0 голосов
/ 30 октября 2018

Я решил это с помощью метакласса , используя его для переопределения способа создания производных классов. При таком подходе все переменные класса, которые нас интересуют, копируют из базовых классов в производный:

class M(type):
  def __new__(cls, name, bases, dct):
    for base in bases:
      for name, prop in base.__dict__.items():
        if type(prop) is int:
          dct[name] = prop
    return super(M, cls).__new__(cls, name, bases, dct)

class A(metaclass=M):
  x = 0
  y = 1
  @classmethod
  def foo(cls):
    print([name for name, prop in cls.__dict__.items() if type(prop) is int])

class B(A):
  z = 3

A.foo()  # prints "['y', 'x']"
B.foo()  # prints "['y', 'x', 'z']"

Кроме того, метакласс может быть определен таким образом, что foo даже не придется запрашивать __dict__ - представляющие интерес переменные могут быть помещены в список вместо изменения __dict__, если это по какой-то причине нужно было избегать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...