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

时间:2016-03-31 17:06:39

标签: 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'>,)

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

3 个答案:

答案 0 :(得分:3)

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")

__bases__表示类派生的基础:

class parent:
    pass

class child(parent,int):
    pass

print(child.__bases__)

但是,如果您询问objecttype之间的奇怪关系:

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

这更像是一个鸡与蛋的问题:哪个先出现了?

答案是PyObject,它在C中定义。

objecttype可用于python解释器之前,它们的基础机制在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

print(isinstance(TYPE,OBJECT))
print(isinstance(OBJECT,TYPE))
print(isinstance(TYPE,TYPE))
print(isinstance(OBJECT,OBJECT))

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

#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

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

答案 1 :(得分:1)

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

这真的很奇怪,感觉就像海龟一样。我之前并没有非常深入研究这个领域,尽管它听起来很有趣和强大。这个解释令人困惑,该页面上的其他信息也是如此,但我感觉就像我有一些启示。无论我是否能清楚地解释清楚,我都不确定,但我会有所作为。

让我们先看看海龟:

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

等等,什么?

objecttype的实例时,type object的实例如何?这就像说:

class Parrot: pass

ex = Parrot()

isinstance(ex, Parrot)
isinstance(Parrot, ex)

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

>>> isinstance(type, type)
True

这应该向你表明,幕后有一些魔力。所以在这一点上,让我们完全忘掉Python(我知道,为什么我们想要做这么可怕的事情?)

一般来说,所有的计算机程序都是1和0&lt; sub> (更准确地说,它们只是一堆逻辑门和电子在&gt; ~2.5 v和〜&lt; 2.5v,但0&s;和1&#39; s足够好了) 。无论你是在汇编,实际的机器代码,Python,C#,Java,Perl,还是其他任何东西中编写的,它们都只是位。

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

对于Python,它是python解释器,它为我们的Python程序提供了意义。有趣的是,我们通常认为是Python的很多内容实际上是用Python编写的(尽管大多数是C语言,对于我们CPython人员,Java用于Jython等)。

现在我们来讨论typeobject。正如文章指出的那样,它们有点特殊。所以,我们知道我们可以创建一个类,然后该类就是一个对象:

>>> class Confusion: pass
...
>>> isinstance(Confusion, object)

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

>>> 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>'

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

>>> Counter.__call__()
5
<__main__.Counter object at 0x7fa03fca4518>

那么这与typeobject之间的关系有什么关系呢?

好吧,某处python创建一系列位object,以及一系列位type,然后将它们连接在一起以某种方式

>>> type.__bases__
(<class 'object'>,)
>>> object.__bases__
()

因为我目前不想查看来源,所以我要先猜测type是先创建的,object是从该类型产生的, type.__bases__设置为(class 'object')。通过在typeobject之间建立这种循环关系,它给出的外观是它只是乌龟一直向下,而真正最后两只乌龟只是站在彼此之上。

我认为 -a /具有一种思维方式,因为它实际上并不是那种东西。就像试图在二维空间中绘制一个三维图形一样,你会遇到问题。

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

答案 2 :(得分:0)

虽然我的第一个答案解决了Python内置变量typeobject之间的矛盾关系,但并不一定要消除关于type和{{ 1}}意味着更大的前景。该答案将说明objectobject在实际可能会遇到的上下文中如何影响其他python对象。

  

在Python中,一切都是type

这意味着语句object将始终为isinstance(x, object)给出任何可能的值True

这也意味着定义的任何类都将被视为对象的子类。因此,x对于任何类总是正确的。

实际上这意味着将在issubclass(x, object)中定义所有python对象的标准操作,例如属性查找和获取内存中对象的大小。它还定义了通常被覆盖的行为,例如转换为字符串或初始化,因此,如果您不在子类中覆盖object__str__,它仍然会做一些合理的事情。

  

__init__是实例化以获得类的类

这意味着所有类都被视为type的实例。因此type对于所有类都是正确的。当我说类时,我的意思是诸如isinstance(x, type)intstrbool关键字创建的变量。

  

一切都是对象-甚至是类。

这意味着所有对象存在的标准行为也适用于类对象。因此,编写class将查找str.join方法并为您提供join

  

type是每种类型的类

以与<method 'join' of 'str' objects>定义int应该做什么或1+3定义字符串方法的方式相同,str定义特定于类型对象的行为。例如,调用一个类对象(如type)将创建该类的新实例-这种创建新对象的行为是在int("34")方法中定义的。

作为一个更具体的示例,请查看type.__call__str.join之间的对偶性

type.mro

因此,每个类都定义了作用于其实例的方法,类本身的行为在>>> x = "hello" >>> str.join # unbound method of strings <method 'join' of 'str' objects> >>> x.join #bound method of x <built-in method join of str object at 0x109bf23b0> >>> hex(id(x)) # the memory address of x as seen above '0x109bf23b0' >>> type.mro #unbound method <method 'mro' of 'type' objects> >>> int.mro #mro method bound to int <built-in method mro of type object at 0x106afeca0> >>> hex(id(int)) # address of int object as seen above '0x106afeca0' >>> int.mro() #mro stands for Method Resolution Order, is related to __bases__ [<class 'int'>, <class 'object'>] 类中进行了定义。

所有对象共有的行为-您通常只是以内置方式注销的那种行为-由type定义,因此所有对象都具有这些行为(除非子类覆盖它:)

P.S。以相同的方式,您可以创建object的子类来创建具有不同行为的特殊字符串对象,也可以创建str的子类来创建具有不同行为的特殊类。这称为元类(类对象的类)和practical applications of using meta-classes are usually abstract。 (双关语意味)