Ответ Джима кажется верным.
Но для тех, кто нуждается по каким-то веским причинам полностью настроенной инстанчек (хорошо, теперь, когда я пишу это, кажется, что у кого-то нет правильной причины хотеть этого, будем надеяться, что я ошибаюсь), метаклассу это может сойти с рук, но это сложно.
Этот класс динамически заменяет фактический класс создаваемого объекта «теневым классом», который является клоном оригинала. Таким образом, нативная «инстанчек» всегда терпит неудачу, и вызывается метакласс.
def sub__new__(cls, *args, **kw):
metacls = cls.__class__
new_cls = metacls(cls.__name__, cls.__bases__, dict(cls.__dict__), clonning=cls)
return new_cls(*args, **kw)
class M(type):
shadows = {}
rev_shadows = {}
def __new__(metacls, name, bases, namespace, **kwd):
clonning = kwd.pop("clonning", None)
if not clonning:
cls = super().__new__(metacls, name, bases, namespace)
# Assumes classes don't have a `__new__` of them own.
# if they do, it is needed to wrap it.
cls.__new__ = sub__new__
else:
cls = clonning
if cls not in metacls.shadows:
clone = super().__new__(metacls, name, bases, namespace)
# The same - replace for unwrapped new.
del clone.__new__
metacls.shadows[cls] = clone
metacls.rev_shadows[clone] = cls
return metacls.shadows[cls]
return cls
def __setattr__(cls, attr, value):
# Keep class attributes in sync with shadoclass
# This could be done with 'super', but we'd need a thread lock
# and check for re-entering.
type.__setattr__(cls, attr, value)
metacls = type(cls)
if cls in metacls.shadows:
type.__setattr__(metacls.shadows[cls], attr, value)
elif cls in metacls.rev_shadows:
type.__setattr__(metacls.rev_shadows[cls], attr, value)
def call(cls, *args, **kw):
# When __new__ don't return an instance of its class,
# __init__ is not called by type's __call__
instance = cls.__new__(*args, **kw)
instance.__init__(*args, **kw)
return instance
def __instancecheck__(cls, other):
print("doing instance check")
print(cls)
print(other)
return False
class A(metaclass=M):
pass
print(type(A))
print(isinstance(A(), A))
У него даже есть механизм синхронизации атрибутов в теневом классе и реальном классе. Единственное, что он не поддерживает, это если классы, обработанные таким образом, действительно реализуют пользовательский __new__
. Если такой __new__
использует super
без параметров, это становится сложным, поскольку параметр super не будет теневым классом.
person
jsbueno
schedule
11.12.2017
__instancecheck__
как метод в обычном классе, экземпляры класса могут использоваться в качестве второго аргументаisinstance
- person drdrez   schedule 14.12.2017