python元类、类型类和对象类

eyh26e7m  于 2023-03-16  发布在  Python
关注(0)|答案(2)|浏览(91)

我很难理解metaclass类型、object类和class类型之间存在的循环关系。
我试着理解python是如何把每件事都变成object.is的,因为每件事都是元类类型的示例,还是因为每件事都是对象类的子类。
如果是因为它是object类的子类,这是否意味着类对象被命名为class pyobj,这是否意味着Python中的所有东西都以pyobj开头?
我知道元类创建的对象是类型/类,然后使用这些类型创建其他对象。
从这里:

>>> isinstance(type, object)
True
>>> isinstance(object,type)
True
>>> issubclass(object,type)
False
>>> issubclass(type,object)
True

可以肯定地说,python首先使用type metaclass创建class对象(为了简洁起见,我简化了metaclass)。

type('object',(),{})

这意味着类对象是类类型的类,并且它不继承其他类的任何属性。
然后创建类类型:

type('type', (object,),{})

隐含类型类是类类型的类,并且它从对象类继承属性。
然后通过继承class对象创建其他类

type('dict', (object,), {})  
type('Animal', (object), {})

类似于创建Animal类,如下所示:

class Animal:
     pass

这是否意味着用于创建类对象的元类仍然是用于创建这个Animal类的元类,还是默认使用的元类类型?
使用的是哪种类型,是元类类型还是在创建对象之后创建的类型类?
用基类对象创建的类类型在哪里起作用?
我还试图通过上面和本文中的所有回答来理解对象和类之间到底发生了什么
我还是很困惑。这两个类在对象创建方面有什么关系?
我会得到这个还是这是一个鸡和蛋的情况?

x9ybnkn6

x9ybnkn61#

Python的核心类型确实存在鸡和蛋的问题。type继承自object,但objecttype的示例。
在Python中,你无法真正推断出objecttype中的哪一个是先定义的,因为在常规的Python代码中,你无法设置它们之间的关系,Python解释器可以在环境设置之前通过调整内部结构来完成这一点,因此,即使类型没有完全预先定义,也没有关系。
在您调用type来创建新的objecttype类型的示例中,您实际上并没有获得与真实的的typeobject等价的对象,因为您的新object类型是内置type元类的示例,而不是您稍后创建的手工type元类。
下面是解释器的大致操作过程。代码实际上并不工作,因为如果不继承object,就不能创建一个新样式的类,也不能重新分配type对象的__class__属性(使object成为type的示例)。如果可以,就可以启动自己的独立类型系统!

my_object = type('my_object', (), {}) # this doesn't work right, it inherits from object
my_type = type('my_type', (my_object,), {})
my_object.__class__ = my_type     # this doesn't work at all (it will raise an exception)
yiytaume

yiytaume2#

如果type是一只鸡,object是一只蛋,那么C就是恐龙(至少在使用最流行的Python实现Cpython时是这样)。Cpython通过使用C生成最常见的对象来加快速度。所以循环引用不是一个问题,从技术上讲,恐龙下了鸡蛋,生下了活鸡。如果这让人伤心,那就不要去想了。
一旦你进入Python领域,把object作为所有东西的根是一个很好的起点,这就是我们在下面的例子中传递类和函数的原因:

def my_func():
    pass

class SimpleClass:
    pass

class MetaClass(type):
    pass

class MetaMadeClass(metaclass=MetaClass):
    pass

for o in (str, 'hello', object, object(), type, SimpleClass, MetaClass, MetaMadeClass, print, my_func):
    print(o)
    print('  ', o.__class__)
    try:
         print('  ', o.__mro__)
    except:
         print('   ---   ')  
    try:
         print('  ', o.__call__)
    except:
         print('   ---   ')  
    print('  ', o.__new__)
    print('  ', o.__init__)

也许有人可以在这里放一个输出表,但我会总结有趣的。
你会注意到很多结果的名字里有“built-in”,这让你知道你不是在处理纯python对象。
在这个例子中,当一个属性在'hello'上找不到时,Python会检查__class__,然后它会按照str的MRO返回str.__init__object.__new__
具有__class__ = type的对象被称为类。这包括strobject甚至type本身!Simple.__call__导致调用type.__call__type中的方法配置对象以传递该类的示例,例如它将__class__设置为适当的值。
我不确定type在技术上是否是一个元类,因为它是生成Python类的C代码,但是它可以被子类化,然后你肯定有一个生成Python类的Python类,它允许你做一些极端的事情,比如把__class__设置为完全不同的东西,或者根本不返回一个示例,但是极端的方法需要一个非常好的理由来做。

关于Cpython的旁注

您可能猜对了,int类型是为了效率而在C中实现的,但即使如此,低int类型的处理方式与高int类型的处理方式也是不同的。

for a, b in [(1, 1), (10**100, 10**100)]:
    print(a is b)

# Output:
#     True
#     False

Cpython继续生成小整数的示例,并在生成较大整数时重用它们。结果是1是对同一个对象的引用,而10**100是两个独立的对象。关键是,如果我可以沉迷于另一个科学类比,日常Python就像牛顿物理学,而你正在进入量子力学的领域。我现在累了......

相关问题