如何重新创建 `object` 和 `type` 在 Python 中保持的相同“基础和实例”关系?

问题描述 投票:0回答:1

最近在学习元类的知识。我了解到

isinstance(object, type)
issubclass(type, object)
。我想写像
object
type
这样的自定义类行为,但是发生循环依赖时如何声明类?伪代码如下:

declare class MyType

class MyObject(metaclass=MyType):
    pass

class MyType(MyObject, type):
    pass

python metaclass
1个回答
0
投票

如上面非常恰当的评论所述:

“”“ 你不能,不是在 Python 中。您可能能够使用 C 扩展,但 Python 使用引导程序来设置该依赖项,这涉及改变在正常情况下不打算改变的内部数据。 – 西尔维奥马约洛 “”.

好吧,这虽然是正确的,但并不完全正确——Python 动态允许以有限的形式改变类基类和继承,甚至对象类,after 创建一个类或对象。

这意味着可以在纯 Python 代码中执行部分相同的引导。

Python 中有一个 second 硬编码关系,您在问题中没有提到:

type
是自己的元类 - 也就是说
type
type
的一个实例:真的无法模拟在纯 Python 代码中。然而,
type
object
的相互关系可以。同样,这没有任何实际用途,并且
object
type
始终作为基类和基元类保持在循环中:没有它们你真的做不了任何事情。

就是说,检查下面的例子。

首先是

type
非常独特,不是因为与
object
的这种关系,而是因为它完成了在引擎盖下实际在 Python 中创建类的所有工作 - 这是很多事情。最终,所有自定义元类都在某个时候调用
type.__new__
来实际创建一个类型 - 所以虽然您的
MyType
可以继承自
MyObject
,但它也必须保留来自
type
的继承(作为其中之一基地) - 这样就可以完成班级创建工作。 (好的 - 最终,有一种方法可以解决它,覆盖正确的方法,并代理对
type
的调用 - 但让我们推迟)。

事实是:要获得这种鸡蛋-母鸡关系,您必须至少更改一个对象after它被创建。

类类(它的元类)创建后不能修改:

class A: pass

class M(A, type): pass

A.__class__ = M

会提高

TypeError: __class__ assignment only supported for mutable types or ModuleType subclasses
。但反过来实际上是可能的:

class M(type): pass

class A(metaclass=M): pass

M.__bases__ = (A, type)

正如我在上面所写的,需要将

type
作为 M 的基础之一 - 试图将其从作业中的基础中删除,将提出:
TypeError: __bases__ assignment: 'A' object layout differs from 'type' 
。但是做
M.__bases__ = (A, type)
工作,并且在这样做之后:

In [18]: isinstance(A, M)
Out[18]: True

In [19]: issubclass(M, A)
Out[19]: True

现在,对于第二部分,如果您根本不想

M
type
继承,只需在
__new__
上实现
__call__
M
就足以拥有一个“工作元类”。 但是,没有办法将
M
作为调用
type.__new__
的第一个参数传递:Python 在内部检查此调用中传递的元类是
type
的“真实”子类。这意味着当您随后请求
A
的类时,它不会使用普通方法说它是“M 类”——但是,我们可以通过实施
__instancecheck__
特殊方法来“伪造”它“元类的元类”中的方法。

请注意,由于

__bases__
assignmen 中的一些限制,以及
__instancecheck__
必须存在于我们要检查其实例的类的元类上(因此,在我们的元类的元类中),我们需要现在还有 2 个中级班。

__instancecheck__
__subclasscheck__
中的代码可以调整以执行一些“真实检查” - 只需返回“True”就足以用于演示目的:

class A: pass


class M(type):
    def __instancecheck__(self, instance):
        return True
    def __subclasscheck__(self, subclass):
        return True
    
class N(A, metaclass=M):
    def __new__(mcls, name, bases, ns):
        cls = type.__new__(type, name, bases, ns) # <- here, M can't be the first argument, as it does not inherit from "type"
        return cls
    def __call__(cls, *args, **kw):
        instance = cls.__new__(cls, *args, **kw)
        if isinstance(instance, cls):
            instance.__init__(*args, **kw)
        return instance
        
class B(metaclass=N): pass

N.__bases__ = (N,)

现在,有了不从类型继承的元类,您可以:

In [42]: isinstance(B, N)
Out[42]: True

In [43]: issubclass(N, B)
Out[43]: True

但是,如果通过

type
进行测试,您将不会看到
N
作为元类:

In [44]: type(B)
Out[44]: type
© www.soinside.com 2019 - 2024. All rights reserved.