Как клонировать класс, использующий super ()? - PullRequest
0 голосов
/ 04 августа 2020

Следующая программа Python:

def clone(cls):
    return type(cls)("Clone" + cls.__name__, cls.__bases__, dict(vars(cls)))

class A:
    def __init__(self):
        super().__init__()

CloneA = clone(A)
CloneA()

вызывает следующую ошибку (CPython 3.8.4 интерпретатор):

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: super(type, obj): obj must be an instance or subtype of type

Как я могу клонировать ( не подкласс) A и избежать этой ошибки?

1 Ответ

0 голосов
/ 04 августа 2020

Просто добавьте атрибут __class__ = cls:

def clone(cls):
    namespace = dict(vars(cls), __class__=cls)
    return type(cls)("Clone" + cls.__name__, cls.__bases__, namespace)

CloneA() вызовы CloneA.__call__(CloneA) разрешены в type.__call__(CloneA), который вызывает CloneA.__new__(CloneA) разрешено в type.__new__(CloneA) для создания экземпляра self из CloneA, за которым следует CloneA.__init__(self), который вызывает A.__init__(self). Наконец, последний вызывает super() (сокращение от super(__class__, self)), который проверяет, что self является экземпляром или подклассом __class__, который принадлежит A, то есть self.__class__ или type(self) является подклассом A. type(self) всегда возвращает CloneA, а self.__class__ может отличаться, как упоминал Гвидо в PEP 3119 :

Кроме того, isinstance(x, B) эквивалентно issubclass(x.__class__, B) or issubclass(type(x), B). (Возможно, type(x) и x.__class__ не являются одним и тем же объектом, например, когда x является прокси-объектом.)

...