繁体   English   中英

为什么 python isinstance() 对于基类是可传递的,而对于元类是不可传递的?

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

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

在第一种情况下:

class A(object):
   pass

class B(A):
    pass

class C(B):
     pass

ic = C()

意味着isinstance(ic,X)对于X等于ABC是真的。

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

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元类的实例,而my_instanceMyClass类的实例,但不是MetaDataElement的实例。

我的解释正确吗? 对此有简单的解释吗?

令人困惑的是MyClass不是DataElementBase的“实例”。 它是元类的一个实例: MetaDataElement ,以及该元类的所有超类的实例(即:“类型”和“对象”)。 就像“普通”类的实例会发生什么一样:

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

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”的关系是“超类”。 所以,如果你问它是否是 DataElementBase 的子类,你会得到 True:

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

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

所以,换句话说:“元类”是“用来构建类的类”,它与创建的类的继承链无关。 相反,给定的对象将始终是其类的任何“超类”的实例。 元类不是其类的超类。

一旦你理解了这一点,你就会注意到“isinstance”和“issubclass”的行为在“非元”类及其实例、“元类”和通过它们创建的类之间是相同的。


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

您编写它的方式,将您的元类与此签名分开,迫使您的代码按照您所做的方式声明类:通过调用显式实例化元类。 它不能用作元类,从class语句及其主体创建新类 - 在这种情况下,Python 使用type.__new__使用的参数调用元类。

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

(类型对象) MetaDataElement的接口是它是一个,除其他外,它继承自DataElementBase my_instance是这样的类吗? 不; 它甚至不像类那样可调用。 它是这样一个类的对象,但是isinstance(my_interface, MetaDataElement)会暗示它这样一个类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM