Python中对象、类型、元类之间的关系
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中对象、类型、元类之间的关系的更多相关文章
- python中对象、类型和元类之间的关系
在python中对象.类型和元类构成了一个微妙的世界. 他们有在这个世界里和平共处,相辅相成.它们遵循着几条亘古不变的定律: 1.python中无处不对象 2.所有对象都有三种特性:id.类型.值 3 ...
- Python面向对象 | 类空间及类之间的关系
一. 类的空间问题 1何处可以添加对象属性 class A: def __init__(self,name): self.name = name def func(self,sex): self.se ...
- php中对象类型与数组之间的转换
1.刚看视频学习的时候看到一个困扰很久的问题, 有时候我们在进行做项目的时候会碰到的一个小问题.举一个小例子. 获取一个xml文件里面的数据. xml.xml文件如下: <?xml versi ...
- python摸爬滚打之day17----类与类之间的关系
1.类与类之间的联系 1.1 依赖关系 类A中使用了类B, 类B作为参数传进类A的方法中被使用. 这种关系中类与类之间的联系是最轻的. class Elephant: def open(self,e ...
- Servlet中常用对象及API类之间的关系
Servlet最常用的对象: 请求对象:ServletRequest和HttpServletRequest,通过该对象获取来自客户端的请求信息 响应对象:ServletResponse和HttpSer ...
- pygame中多个class类之间的关系
用一个实例介绍一下有关pygame中不同类之间的通信,详细介绍在代码段有标注,感兴趣的可以复制代码试试: import pygame import sys # -------------------- ...
- 非常易于理解‘类'与'对象’ 间 属性 引用关系,暨《Python 中的引用和类属性的初步理解》读后感
关键字:名称,名称空间,引用,指针,指针类型的指针(即指向指针的指针) 我读完后的理解总结: 1. 我们知道,python中的变量的赋值操作,变量其实就是一个名称name,赋值就是将name引用到一个 ...
- 小学生绞尽脑汁也学不会的python(面对对象-----类与类之间的关系)
小学生绞尽脑汁也学不会的python(面对对象-----类与类之间的关系 1. 依赖关系. 最轻的一种关系 在方法中引入另一个类的对象 class Elephant: def __init__(sel ...
- Python面向对象02/类的空间问题、类与对象之间的关系、类与类之间的关系
Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 目录 Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 1. 类的空间问题 2. 类与对象之间 ...
随机推荐
- Qt:QDateTime
0.说明 提供时间日期的表达和相关函数. QDateTime通过日期+时间来构造一个日期时间.它综合了QDate和QTime的所有特性. 它可以通过系统时钟来获取当前DateTime.它还提供了比较时 ...
- Pandas:plot相关函数
0.注意事项 及 各种错误 1)绘制bar图时,如果出现重复的x值被合并到一个情况(导致X轴应该显示内容有缺失),可能是由于Pandas版本太低: 2)无法设置中文title,在代码中加入两句话: p ...
- 四、Java基础
Java基础 在开始学习Java基础之前,我们先来学习一下IDEA 打开IDEA,新建一个项目(New Project),选择空项目(Empty Project),填写项目名(Project name ...
- LeetCode-009-回文数
回文数 题目描述:给你一个整数 x ,如果 x 是一个回文整数,返回 true :否则,返回 false . 回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数.例如,121 是回文,而 1 ...
- LeetCode-081-搜索旋转排序数组 II
搜索旋转排序数组 II 题目描述:已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同. 在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums ...
- 微服务从代码到k8s部署应有尽有系列(十二、链路追踪)
我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...
- C#发送邮件,可带有Excel附件
记录工作中遇到发邮件带附件的需求,新建控制台应用程序,目录下创建好所需要的定义好的Excel模板! class Program { static string newExcelPath = strin ...
- Mybatias
Mybatis 1.简介 1.1丶什么是Mybaties MyBatis 是一款优秀的持久层框架, 它支持自定义 SQL.存储过程以及高级映射. MyBatis 免除了几乎所有的 JDBC 代码以及设 ...
- LGP3126题解
这道题还有点意思. 路径要求是一个回文串,回文串立马枚举中点.中点只可能在对角线上. 枚举对角线上的一个点,然后两边的路径必须完全相同. 既然路径上的字符必须完全相同,那么每个前缀也必须完全相同. 考 ...
- LGP5044口胡
套路题. 对于这一类与 \(\max\) 有关的题,优先考虑笛卡尔树. 建出笛卡尔树,考虑处理以某个点 \(u\) 举办会议时,参加会议的成本. 这里考虑询问区间为 \([1,n]\). 明显 \(u ...