这是一个后续问题(与我提出的这个问题有关)但它足够复杂,我认为最好开始一个新问题。
以前,我发现无论出于何种原因,我都有:
isinstance([], UserString) == True
但这显然是不对的。经过一堆挖掘,我认为我的其他代码导致了这个问题,但我不知道这怎么可能。
这是可以重现上述问题结果的最少代码:
if __name__ == "__main__":
def func_decorator(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
return wrapper
def class_decorator(cls):
# set of callable function names already been decorated/inspected
handled_funcs = {'__new__', '__init__', '__del__', '__getattr__', '__getattribute__', '__class__'}
for key in cls.__dict__:
# Only callable functions are decorated
value = getattr(cls, key)
if not callable(value):
continue
handled_funcs.add(key)
setattr(cls, key, func_decorator(value))
# Handle the remaining base classes (skip Mixin)
for base in cls.__mro__[2:]:
for key in base.__dict__:
value = getattr(base, key)
if not callable(value) or key in handled_funcs:
continue
handled_funcs.add(key)
setattr(cls, key, func_decorator(value))
return cls
class Mixin():
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
class_decorator(cls)
class MyUserString(Mixin, UserString):
def __init__(self, seq, *, synthesized=False):
super().__init__(synthesized, seq)
print(isinstance([], UserString)) # this will print True
我删除了大部分其他代码,这些代码实际上做了我需要的有用的事情。基本上,我MyUserString
使用__init_subclass__
in 进行装饰,Mixin
以便 inMyUserString
及其基类(我跳过Mixin
)中的所有方法都由func_decorator
. 在装饰过程中,我按照MRO,跳过已经根据处理过的方法handled_funcs
(即handled_funcs有所有不应该被装饰的方法,要么是我不希望它们被装饰,要么是因为它们已经被装饰,例如,__new__
我在一开始就添加)。
现在,我发现有趣的是,如果我__subclasshook__
在集合中添加,我得到了正确的结果,即
isinstance([], UserString) == False
. 但为什么?func_decorator
简单地返回与原始函数相同的值,更重要的是,UserString
甚至没有被修饰class_decorator
(我认为,因为setattr
总是为 设置属性cls
,即MyUserString
,但也许我错了)?
我知道UserString
继承自ABC
并ABC
以某种方式定义__subclasshook__
了isinstance
...但是我不能将两个和两个放在一起!有人可以解释发生了什么吗?