дескриптор '__dict__' для объектов не применяется к объекту с использованием type () - PullRequest
2 голосов
/ 14 апреля 2020

Я получаю странное поведение при использовании type() в Python 3.6+. Я использую его для динамического переноса всех классов из внешней библиотеки и получаю сообщение об ошибке при вызове self.__dict__. Рассмотрим следующий пример:

class A(object):
    def __init__(self):
        print(self.__dict__)

class B(A):
    def __init__(self):
        super(self.__class__, self).__init__()

B() # this works

, но когда я делаю эквивалентную вещь, используя type, я получаю эту странную ошибку:

class A(object):
    def __init__(self):
        print(self.__dict__)

class B(object):
    def __init__(self):
        super(self.__class__, self).__init__()

# C is a class which is B that inherits from A
C = type('C', (A,), B.__dict__.copy())
C()
# TypeError: descriptor '__dict__' for 'B' objects doesn't apply to 'C' object

Как мне исправить это с помощью type() ?

[TLDR: ответ @ fritzo исправляет ошибку, но этот дизайн вводит другие проблемы наследования. Принятый ответ @ juanpa.arrivillaga дает лучший обходной путь]

1 Ответ

1 голос
/ 14 апреля 2020

Исходя из ваших комментариев о желании сделать это динамически , вы могли бы использовать super, но вы должны понимать, как это работает, super дает вам следующий метод в порядке разрешения методов , так что вы do имеете доступ к методам в A из вашего миксина, но вы должны правильно использовать super, чтобы что-то подобное могло работать:

In [1]: class Mixin:
   ...:     def foo(self):
   ...:         if hasattr(self, 'whatever'):
   ...:             print("doing Mixin.foo stuff")
   ...:         else:
   ...:             return super().foo()
   ...:

In [2]: class A:
   ...:     def foo(self):
   ...:         print("doing A.foo stuff")
   ...:

In [3]: class C(Mixin, A):
   ...:     pass
   ...:

In [4]: c = C()

In [5]: c.foo()
doing A.foo stuff

In [6]: c.whatever = 42

In [7]: c.foo()
doing Mixin.foo stuff

Однако я не уверен, насколько это рекомендуется. Но это возможно.

Обратите внимание, и под динамикой c я имею в виду что-то вроде этого работает:

In [9]: class Mixin:
   ...:     def foo(self):
   ...:         if hasattr(self, 'whatever'):
   ...:             print("doing Mixin.foo stuff")
   ...:         else:
   ...:             return super().foo()
   ...: class A:
   ...:     pass
   ...:
   ...: class B:
   ...:     def foo(self):
   ...:         print("doing B.foo stuff")
   ...:
   ...: class C(Mixin, A, B):
   ...:     pass
   ...:

In [10]: c = C()

In [11]: c.foo()
doing B.foo stuff

In [12]: c.whatever = 42

In [13]: c.foo()
doing Mixin.foo stuff
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...