Python中的元类、类型类和对象类

3
我很头疼,试图理解元类类型、对象类和类类型之间的循环关系。我正在尝试理解Python如何将所有东西都变成对象。是因为所有东西都是元类类型的实例,还是因为所有东西都是object类的子类。如果是因为是object类的子类,这是否意味着将类对象命名为pyobj,那么Python中的所有东西都以pyobj开头?我知道由元类创建的对象是类型/类,这些类型/类随后用于创建其他对象。
>>> isinstance(type, object)
True
>>> isinstance(object,type)
True
>>> issubclass(object,type)
False
>>> issubclass(type,object)
True

可以说Python首先使用type元类创建类对象(为了简洁起见,我简化了元类)是安全的。
type('object',(),{})

这意味着类对象是一种类类型,它不继承任何其他类的属性。然后它创建类类型:
type('type', (object,),{})

暗示类型类是类类型的类,并且它继承了对象类的属性。然后通过从类对象继承来创建其他类。
type('dict', (object,), {})  
type('Animal', (object), {})

类似于创建一个Animal类的方式如下:
class Animal:
     pass

这是否意味着用于创建类对象的元类仍然是用于创建此Animal类的元类类型,还是默认使用元类类型?
正在使用哪种类型,是元类类型还是在创建对象后创建的类型类?
基类对象创建的类类型何时发挥作用?
我也试图从上面所有的回复和这篇文章中理解对象和类之间到底发生了什么http://www.cafepy.com/article/python_types_and_objects/python_types_and_objects.html 我仍然感到困惑。这两个类在对象创建方面的关系是什么?
我会明白吗,还是这是一个鸡生蛋的问题?

你有没有阅读过《语言参考》中的3.3.3. 自定义类创建一节? - undefined
2个回答

2
Python的核心类型确实存在一种鸡生蛋的情况。type继承自object,但是object是type的一个实例。
在Python中,你无法推断出object和type哪个先定义,因为在常规的Python代码中,你不能设置它们之间的关系。Python解释器可以通过在环境设置之前调整内部来完成这个过程,所以如果类型没有完全定义,也没有关系。
在你调用type创建新的object和type类型的示例中,你实际上并没有得到与真正的type和object等价的对象,因为你的新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)

0
如果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__)

也许有人可以在这里放置一个输出表格,但我会总结一些有趣的内容。
您会注意到很多结果的名称中都有“内置”,这告诉您它们不是纯 Python 对象。
在这个例子中,当在'hello'上找不到属性时,Python 会检查__class__。然后它将遵循str的MRO返回str.__init__和object.__new__。
具有__class__ = type的对象称为类。这包括str、object甚至type本身!在这个例子中,Simple.__call__导致调用type.__call__。正是type中的方法配置了一个对象,使其成为该类的实例,例如设置__class__为适当的值。

我不确定type在技术上是否是元类,因为它是用C代码创建Python类的,但它可以被子类化,然后你肯定有一个创建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 就像牛顿物理学,而你正在进入量子力学的领域。我现在很累...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接