Python里的对象、类型和元类的关系很微妙也很有意思。

1989年圣诞节期间,上帝很无聊,于是创造了一个世界。

对象

在这个世界的运转有几条定律。

1.一切都是对象

对象(object)是这个世界的基本组成单位,所有的的事物都由对象构成。

什么是对象?不同的语言对对象的定义不尽相同。在Python的世界里,对象是数据的一种抽象表示。如果看了Python源码,事情就很好解释了,所有能通过PyObject类型的指针访问的都是对象。整数、字符串、元组、列表、字典、函数、模块、包,栈等都是对象。

圣经提到

2.所有对象都有三种特性: id、类型、值

id是一个对象的编号,每个对象天生都有一个与众不同的编号(目前实现是对象的地址).用id()能看到对象的id

>>> id(1)
140657675012776

每个对象都会有类型(type),类型就像是商品上印的生产厂商一样,标识自己被谁生产出来。用type()可以看到对象的类型

>>> type(1)
<type 'int'>
>>> class A(object): pass
...
>>> a = A()
>>> type(a)
<class '__main__.A'>

值是对象的价值所在。各种各样的对象保存着各种各样的值,Python的世界才会如此多彩。有的对象值永远不会变,叫不可变对象(immutable);有的对象值可以变,叫可变对象(mutable)。

再说一次:Python世界里,一切都是对象

类型

类(class)就是生产出对象的模具(本文只讨论new-style class,classic class不在讨论范围内)。上面说到,每个对象天生都会有个铭牌,写着自己的类型。在Python里,类(class)和型(type)指的是同一件东西。汉字真是精妙,类和型放在一块念是多么的自然。

3.每个对象都是由对应的类创建出来的

由这个定律很容易理解上文说到的,每个对象都有对应类型。类很像工厂里生产产品的模具,它负责对象的创建,决定了对象将被塑造成什么样,有什么属性、函数。

类可以继承和派生。虽然有点勉强,但姑且这么理解吧。类型B继承类型A,就像相当于模具B是以模型A为原型做出来的。生产出模具B的不是模具A,但模具B是模仿模具A而生产出来的,模具B生产出来的对象拥有模具A生产出来的对象类似的特性。模具B如果以模具A为原型生产出来,模具B身上会络上模具A的版权标识(就当做版权保护吧)。用B.__bases__可以看模具B的印记。聪明的你可能已经注意到了,bases是复数,也就是说模具B可以以多个模具为原型,即多重继承。

>>> class A(object): pass
...
>>> class B(A): pass
...
>>> A.__bases__
(<type 'object'>,)
>>> B.__bases__
(<class '__main__.A'>,)

这里注意,模具的版权标识跟对象的类型不一样。每个对象都会有类型,表示自己是哪个模具生产出来的。而模具的版权标识只有模具才会有,标识表示的是这个模具的设计原型哪个模具,并不表示这个模具是由这个原理模具生产出来的。

这里必须要提一下一个特殊的模具,堪称模具之母的模具:object。这个object不是上文说的对象,上文的对象是一个抽象的概念,这里的object是一个具体的模具。所有的模具(除了object自己)沿着印记向上追溯,最后肯定到object。也就是说,所有除了object自己以外的类,都直接或间接地继承了object,无论是内置的(buit-in)还是自定义的(user-defined)。另一方面看,所有对象都直接或间接由模具object生产出来。如果有兴趣的话,用type()把想查看对象的类型找到,再用__baess__向上查找,最后肯定会到object。从源码的角度看,object就是上文提到的PyObject。这跟Python里所有的对象都能用PyObject的指针访问是有关系的。

元类

定律1说到,一切都是对象,类型也是对象。相比很多语言,这一点非常特别。

>>> id(A)
140548933792976
>>> type(A)
<type 'type'>
>>> dir(A)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

可以看到,类型也像其他对象那样,有id,有类型,有值。它可以当变量、类成员、函数参数。有意思吧?更有意思的在后头。

定律3说到,任何对象都是由类型创建出来的。那类型这种对象是由谁创建出来的呢?继续拿模具来说,生产模具的模具是谁呢?模具的模具:元类(metaclass)。元类跟其它模具不同之处在于,它生产出来的是不是一般的对象,是模具。是不是很神奇?有了元类我们就可以在程序运行时动态生成类了。我们可以根据各种数据和配置,动态地定制我们所需要的类。这里不讨论元类的使用方法。不过元类除了能生产模具之外,跟其它模具相比无其它特别的地方。

有趣的问题又来了,根据定律1,元类也是对象吧,元类是谁生产出来的?元类是模具,生产模具的模具还是元类,所以元类的类型也应该是元类。继续追问下去,元类的元类的元类也是元类……这么追溯到源头(再强调一下,本文只讨论new-style class),就是一个特殊的元类:type。什么?type不是个查看类型的函数吗?通过help(type)可以知道,type是个类。type()如果传1个对象进去,type会返回这个对象的类型,这是我们熟知的用法;如果传3个对象进去,会生产出一个新的类出来。为什么会把两个功能放到一个类里做呢?可能是历史原因吧。再追问下去,这个终极的元类的类型是什么呢?上帝为了世界设定的统一,使type的类型是它自己。模具把自己生产出来了?这个下面讨论。

type引来的问题不只这些。

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

我们看到,type这个模具是object为原型造的,而生产object的模具却是type。鸡先生蛋还是蛋先生鸡?Python这个世界是运行在虚拟机上的。世界创建之初虚拟机就把type和object都造出来了。object一出世,生产的模具就写着是type;type一出世,模板的版权印记就记着object。他们一开始就存在了,无所谓谁先谁后。同理,type是不是自己把自己创建也来的问题也一样。

总结

此文把对象、类型、元类的关系画成了这幅图。三个框分别表示元类、类型、一般对象。把虚线看成产品与模具的关系,实线看成模具与原型的关系,是不是一目了然?

转自:http://www.lightxue.com/relationship-among-object-class-metaclass-in-python

Python中对象、类型、元类之间的关系的更多相关文章

  1. python中对象、类型和元类之间的关系

    在python中对象.类型和元类构成了一个微妙的世界. 他们有在这个世界里和平共处,相辅相成.它们遵循着几条亘古不变的定律: 1.python中无处不对象 2.所有对象都有三种特性:id.类型.值 3 ...

  2. Python面向对象 | 类空间及类之间的关系

    一. 类的空间问题 1何处可以添加对象属性 class A: def __init__(self,name): self.name = name def func(self,sex): self.se ...

  3. php中对象类型与数组之间的转换

    1.刚看视频学习的时候看到一个困扰很久的问题, 有时候我们在进行做项目的时候会碰到的一个小问题.举一个小例子.  获取一个xml文件里面的数据. xml.xml文件如下: <?xml versi ...

  4. python摸爬滚打之day17----类与类之间的关系

    1.类与类之间的联系 1.1  依赖关系 类A中使用了类B, 类B作为参数传进类A的方法中被使用. 这种关系中类与类之间的联系是最轻的. class Elephant: def open(self,e ...

  5. Servlet中常用对象及API类之间的关系

    Servlet最常用的对象: 请求对象:ServletRequest和HttpServletRequest,通过该对象获取来自客户端的请求信息 响应对象:ServletResponse和HttpSer ...

  6. pygame中多个class类之间的关系

    用一个实例介绍一下有关pygame中不同类之间的通信,详细介绍在代码段有标注,感兴趣的可以复制代码试试: import pygame import sys # -------------------- ...

  7. 非常易于理解‘类'与'对象’ 间 属性 引用关系,暨《Python 中的引用和类属性的初步理解》读后感

    关键字:名称,名称空间,引用,指针,指针类型的指针(即指向指针的指针) 我读完后的理解总结: 1. 我们知道,python中的变量的赋值操作,变量其实就是一个名称name,赋值就是将name引用到一个 ...

  8. 小学生绞尽脑汁也学不会的python(面对对象-----类与类之间的关系)

    小学生绞尽脑汁也学不会的python(面对对象-----类与类之间的关系 1. 依赖关系. 最轻的一种关系 在方法中引入另一个类的对象 class Elephant: def __init__(sel ...

  9. Python面向对象02/类的空间问题、类与对象之间的关系、类与类之间的关系

    Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 目录 Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 1. 类的空间问题 2. 类与对象之间 ...

随机推荐

  1. 用RecyclerView实现列表视图

    RecyclerView能够灵活实现大数据集的展示,视图的复用管理比ListView更好,能够显示列表.网格.瀑布流等形式,且不同的ViewHolder能够实现item多元化的功能.但是使用起来会稍微 ...

  2. java 读取xlsx文件

    public class ReadExcel { public static void main(String[] args) { Workbook wb = null; Sheet sheet = ...

  3. Pycharm:设置完Anaconda后报错TypeError: an integer is required (got type bytes)

    背景:安装了最新版本的Anaconda3.9后,在Pycharm中设置Python Interpreter为这个最新版本Anaconda文件下的python.exe后,控制台无法启动并报错TypeEr ...

  4. php 23种设计模型 - 单例模式

    单例模式(Singleton) 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一 ...

  5. SSH 免密码认证登陆

    检查是否已安装ssh rpm -qa |grep ssh 如未安装可以重新安装 yum install -y openssl openssh-server 修改配置 vim  /etc/ssh/ssh ...

  6. LGB+XGB+CNN一般写法

    现在的比赛,想要拿到一个好的名次,就一定要进行模型融合,这里总结一下三种基础的模型: - lightgbm:由于现在的比赛数据越来越大,想要获得一个比较高的预测精度,同时又要减少内存占用以及提升训练速 ...

  7. 1.1 STL基本概念

    文章目录 1 STL概述 1.1 STL基本概念 1.2 STL 六大组件 1.3 STL优点 2.1 容器 2.2 算法 2.3 迭代器 2.4 示例 1 STL概述 STL是StandardTem ...

  8. ArcMap操作随记(2)

    1.空间校正 变换-仿射 仅发生偏移 橡皮页变化 形状改变 变换-投影 旋转,改变角度 变换-相似 改变大小.形状不变 2.计算行列号 Int(([POINT_Y]-1273.143242)/30)+ ...

  9. jmeter关于入参转码encode问题

    我们的工作中,通过抓包经常会发现有很多入参都是被encode过一层,形成了如上图所示的样子: 这些参数我们是可以通过fiddler去转码的:但是如果我们要做jmeter的脚本,不可能每一次都手动去转码 ...

  10. 关于深搜dps

    哈哈,我又来了! 但是!今天我又带来了让人开心到窒息的 ----深搜dps 其实关于深搜,概念没啥可讲的,总结一句话概括就是:一直往下搜,直到满足条件的,再回来,沿着下一条路搜,直到把路全走完为止.. ...