为什么 python isinstance() 可传递给基数 类 而不传递给 meta类?

Why is python isinstance() transitive with base classes and intransitive with metaclasses?

我是 metaclasses 的新手,可能会以意想不到的方式使用它们。我感到困惑的是 isinstance() 方法在处理 subclasses 时似乎具有传递行为,但在处理 metaclasses.

时却没有

第一种情况:

class A(object):
   pass

class B(A):
    pass

class C(B):
     pass

ic = C()

暗示 isinstance(ic,X) 对于 X 等于 ABC.

为真

另一方面,这是一个元class示例:

class DataElementBase(object):
    def __init__(self,value):
        self.value = self.__initialisation_function__(value)

class MetaDataElement(type):
    def __new__(cls,name,initialisation_function, helptext ):
        result = type.__new__(cls,name,(DataElementBase,), dict(help=helptext) )
        result.__initialisation_function__  = staticmethod(initialisation_function)
        return result


###  test code  ####

# create a class from the metaclass
MyClass = MetaDataElement( 'myclass', float, "Value is obtained as float of user input" )

# create an instance of the class
my_instance = MyClass( '4.55' )

print ( 'MyClass is instance of MetaDataElement? %s' % isinstance( MyClass, MetaDataElement ) )
print ( 'MyClass is instance of DataElementBase? %s' % isinstance( MyClass, DataElementBase ) )
print ( 'my_instance is instance of MyClass? %s' % isinstance( my_instance, MyClass ) )
print ( 'my_instance is instance of MetaDataElement? %s' % isinstance( my_instance, MetaDataElement ) )
print ( 'my_instance is instance of DataElementBase? %s' % isinstance( my_instance, DataElementBase ) )

产量:

MyClass is instance of MetaDataElement? True
MyClass is instance of DataElementBase? False
my_instance is instance of MyClass? True
my_instance is instance of MetaDataElement? False
my_instance is instance of DataElementBase? True

也就是说,MyClassMetaDataElement metaclass的一个实例,而my_instanceMyClass class的一个实例] 但不是 MetaDataElement.

我的解释正确吗?有没有简单的解释?

isinstance 的基本目的是检查对象是否提供 接口 。例如,(类型的对象)DataElementBase 的接口可能包括它具有 value 属性。事实上,my_instance.value 是 4.55。

(类型的对象)MetaDataElement 的接口是它是一个 class,除其他外,它继承自 DataElementBase. my_instance是这样的class吗?不;它甚至不能像 classes 那样被调用。它是这样一个 class 的一个 object,但是 isinstance(my_interface, MetaDataElement) 意味着它 这样一个 class.

令人困惑的是 MyClass 不是 DataElementBase 的“实例”。它是 metaclass: MetaDataElement 的实例,以及该 metaclass 的所有超classes 的实例(即:“type”和“object” ).就像“普通”实例发生的情况一样 classes:

将您的代码片段粘贴到交互式解释器中我可以做到:

In [96]: isinstance(MyClass, MetaDataElement)
Out[96]: True

In [97]: isinstance(MyClass, type)
Out[97]: True

In [98]: isinstance(MyClass, object)
Out[98]: True

In [99]: MyClass.__mro__
Out[99]: (__main__.myclass, __main__.DataElementBase, object)

“DataElementBase”与“MyClass”的关系是“superclass”。所以,如果你问它是否是 DataElementBase 的子class,你会得到 True:

In [100]: issubclass(MyClass, DataElementBase)
Out[100]: True

class 碱基作为调用 type.__new__ 的第三个参数传递。

所以,换句话说:一个“metaclass”是“用来构建一个class的class”,与继承链无关创建的class。相反,给定对象将始终是其 class 的任何“superclass”的实例。 metaclass 不是其 class.

的超class

一旦理解了这一点,您就会注意到“isinstance”和“issubclass”的行为在“非元”classes 及其实例中是相同的,而“元classes" 和通过它们创建的 classes。


在一条不相关的通知中,尽管您的代码按原样工作,但不鼓励这样做。:metaclass __new__ 方法的签名应符合 type.__new__ - 并接收 metaclass 本身、名称、基础、命名空间和可选关键字参数。

你写的方式,从这个签名中分离你的元class强制你的代码声明classes你的方式:通过显式实例化元class称呼。它不能用作从 class 语句及其主体创建新的 class 的 metaclass - 在这种情况下,Python 调用 metaclass 与 type.__new__.

使用的参数