python中类型和对象之间的关系

use*_*629 6 python

我正在阅读http://blog.thedigitalcatonline.com/blog/2014/09/01/python-3-oop-part-5-metaclasses/#.Vv1T7zG1XGA,其中包含:

因为在Python中一切都是对象,所以一切都是类的实例,甚至是类.好吧,type是实例化的类来获取类.所以请记住:object是每个对象的基础,type是每个类型的类.听起来令人费解?这不是你的错,不用担心.然而,只是为了让你完成整理,这就是Python的基础

>>> type(object)
<class 'type'>
>>> type.__bases__
(<class 'object'>,)
Run Code Online (Sandbox Code Playgroud)

我无法理解这一点,任何人都可以用不同的方式解释这种关系,以使其更清晰吗?

Tad*_*sen 5

之间的关系type(x)与 的结果基本相同x.__class__

for obj in (object,type,1,str):
    assert type(obj) is obj.__class__

print("type(obj) and obj.__class__ gave the same results in all test cases")
Run Code Online (Sandbox Code Playgroud)

__bases__表示派生类的基础:

class parent:
    pass

class child(parent,int):
    pass

print(child.__bases__) # prints (<class '__main__.parent'>, <class 'int'>)
Run Code Online (Sandbox Code Playgroud)

但是,如果您询问object和之间的奇怪关系type

   # are `object` and `type` both instances of the `object` class?
>>> isinstance(object, object) and isinstance(type, object)
True
   # are they also instances of the `type` class?
>>> isinstance(object, type) and isinstance(type, type)
True
   # `type` is a subclass of `object` and not the other way around (this makes sense)
>>> [issubclass(type, object), issubclass(object, type)]
[True, False]
Run Code Online (Sandbox Code Playgroud)

这更像是先有鸡还是先有蛋的问题:哪个先有?

答案是PyObjectC中定义的。

object在 python 解释器可以使用或之前,type它们的底层机制是用 C 定义的,并且在定义后实例检查将被覆盖。(像抽象类一样,参见PEP 3119

你可以将其视为类似于以下 python 实现:

#this wouldn't be available in python
class superTYPE(type):
    def __instancecheck__(cls,inst):
        if inst ==TYPE:
            return True
        else:
            return NotImplemented #for this demo
    
class TYPE(type,metaclass=superTYPE):
    def __instancecheck__(cls,inst):
        if inst in (OBJECT,TYPE):
            return True
        else:
            return NotImplemented #for this demo

class OBJECT(metaclass=TYPE):
    pass

# these all pass
assert isinstance(TYPE,OBJECT)
assert isinstance(OBJECT,TYPE)
assert isinstance(TYPE,TYPE)
assert isinstance(OBJECT,OBJECT)
Run Code Online (Sandbox Code Playgroud)

实际上它可能更好地表示为:

#this isn't available in python
class superTYPE(type):
    def __instancecheck__(cls,inst):
        if inst in (TYPE,OBJECT):
            return True
        else:
            return NotImplemented #for this demo
    
class OBJECT(metaclass=superTYPE):
    pass


class TYPE(OBJECT):
    pass
Run Code Online (Sandbox Code Playgroud)

但如果你想确切地知道它是如何工作的,你需要查看用 C 编写的源代码。

  • 感谢您花时间回答这个问题。 (2认同)

Way*_*ner 1

TL;DR - 可能不是。但我尝试过。

这真的很奇怪,感觉就像乌龟一路向下。事实上,我以前并没有深入研究过这个领域,尽管它听起来很有趣而且很强大。这个解释很令人困惑,该页面上的其余信息也是如此,但我觉得我得到了一些启示。我不确定是否能解释清楚,但我会尝试一下。

我们先来看看海龟:

>>> isinstance(type, object)
True
>>> isinstance(object, type)
True
Run Code Online (Sandbox Code Playgroud)

等等,什么?

object的实例如何type,何时type是 的实例object?感觉就像是在说这样的话:

class Parrot: pass

ex = Parrot()

isinstance(ex, Parrot)
isinstance(Parrot, ex)
Run Code Online (Sandbox Code Playgroud)

应该是True两次。但显然不是。甚至(正如 Tadhg McDonald-Jensen 指出的那样)

>>> isinstance(type, type)
True
Run Code Online (Sandbox Code Playgroud)

这应该向您表明幕后正在发生一些魔法。所以在这一点上,让我们完全忘记Python(我知道,为什么我们会想做这么可怕的事情?)

一般来说,所有计算机程序都是 1 和 0 (更准确地说,它们只是一堆>~2.5v 和~<2.5v 的逻辑门和电子,但 0 和 1 就足够了)。无论您是用汇编语言、实际机器代码、Python、C#、Java、Perl 还是其他语言编写它 - 它们都只是位。

如果您编写一个类定义,那么该类只是位。该类的实例只是更多的位。编程语言、编译器和解释器只是更多的位。

就 Python 而言,解释python器为 Python 程序的各个位赋予了意义。有趣的是,我们通常认为是 Python 的很多内容实际上是用 Python 编写的(尽管其中大部分是 C,对于我们 CPython 人员来说是 C,对于 Jython 来说是 Java 等)。

现在我们来谈谈我们称之为type和 的东西object。正如文章所指出的,它们有点特别。所以,我们知道我们可以创建一个类,然后该类就是一个对象:

>>> class Confusion: pass
...
>>> isinstance(Confusion, object)
Run Code Online (Sandbox Code Playgroud)

如果您考虑一下,这是有道理的 - 您可能已经创建了类级变量:

>>> class Counter:
...  count = 0
...  def __init__(self):
...   Counter.count += 1
...   print(self.count)
...
>>> Counter()
1
<__main__.Counter object at 0x7fa03fca4518>
>>> Counter()
2
<__main__.Counter object at 0x7fa03fca4470>
>>> Counter()
3
<__main__.Counter object at 0x7fa03fca4518>
>>> Counter()
4
<__main__.Counter object at 0x7fa03fca4470>
>>> Counter.count
4
>>> Counter.__repr__(Counter)
'<type object at 0x1199738>'
Run Code Online (Sandbox Code Playgroud)

但正如最后一个示例所示(并在帖子中提到),类声明,您所得到的class SomeClass: pass,类的声明实际上是另一个类的实例。特别是,它是该类的一个实例type。调用该实例(我们称之为类)时将生成其自身的实例

>>> Counter.__call__()
5
<__main__.Counter object at 0x7fa03fca4518>
Run Code Online (Sandbox Code Playgroud)

type那么这一切与和之间的关系有什么关系object呢?

好吧,在某个地方python创建了一系列位objecttype然后将它们连接在一起,这样

>>> type.__bases__
(<class 'object'>,)
>>> object.__bases__
()
Run Code Online (Sandbox Code Playgroud)

因为我目前不想查看源代码,所以我将猜测type首先创建的,并且object是从该类型生成的,并且type.__bases__设置为(class 'object'). type通过在和 之间创建这种循环关系object,它看起来就像是一直向下的海龟,而实际上最后两只海龟只是站在彼此之上。

我认为没有比文章描述更好的方法来解释这里发生的事情了——至少在经典的 OOP is-a/has-a 思维方式中,因为它实际上不是那样的事情。就像尝试在 2d 空间中绘制 3d 图形一样,您将会遇到问题。

它只是两组位,其中的一些位恰好是彼此的地址。