面向对象【day08】:类的起源与metaclass(二)
本节内容
1、概述
2、类的起源
3、__new__方法
4、__metaclass__方法
一、概述
前面我们学习了大篇幅的关于类,通过类创建对象,那我们想知道这个类到底是怎么产生的呢?它的一切来源是什么?还有对象,对象是通过什么方法创建的,现在我们一头雾水,行的,下面我们就来揭开类的面纱,看看类和对象到底是怎么创建的,通过什么创建的。
二、类的起源
2.1 传统创建类
|
1
2
3
4
5
|
class Foo(object): def __init__(self,name): self.name = namef = Foo("shuaigaogao") |
f 是通过 Foo 类实例化的对象,其实,不仅 f 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象,按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。
|
1
2
|
print(type(f)) #输出:<class '__main__.Foo'> 表示:f 对象由Foo类创建print(type(Foo)) #输出:<class 'type'> 表示:Foo类对象由 type 类创建 |
所以,f对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建
2.2 type创建类
说明: type创建类的格式,类名 = type('类名',(父类,),{'方法名':方法的内存地址})
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
def func(self): #创建方法 print("hello {0}".format(self.name))def __init__(self,name): #创建构造方法 self.name = name#通过type创建类,如果是经典类的话则写成:Foo = type("Foo",(),{"talk":func,"__init__":__init__})Foo = type("Foo",(object,),{"talk":func,"__init__":__init__}) f = Foo("shuaigaogao") #创建对象f.talk()#输出hello shuaigaogao |
总结:类 是由 type 类 实例化产生的
值得注意的是,新式类的写法,在继承父类那边,你继承一个父类后面就要加一个逗号,加逗号,它就把它当做一个元组,不加逗号,就是一个值了

三、__new__方法
3.1 概念
new方法是类自带的一个方法,可以重构,__new__方法在实例化的时候也会执行,并且先于__init__方法之前执行
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Foo(object): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__",cls, *args, **kwargs) return object.__new__(cls)f = Foo("shuaigaogao")#输出Foo __new__ <class '__main__.Foo'> shuaigaogao #执行了new方法Foo __init__ #执行了__init__方法 |
3.2 new方法作用
作用:所有对象都是通过new方法来实例化的,new里面调用了init方法,所以在实例化的过程中先执行的是new方法,而不是init方法。
①重构__new__方法
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Foo(object): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__",cls, *args, **kwargs)f = Foo("shuaigaogao") #实例化#输出Foo __new__ <class '__main__.Foo'> shuaigaogao |
由上面的例子看出,没有执行__init__方法
②重构__new__方法,并继承父类的__new__方法
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Foo(object): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): #cls相当于传入类Foo print("Foo __new__",cls, *args, **kwargs) return object.__new__(cls) #继承父类的__new__方法,这边必须以返回值的形式继承f = Foo("shuaigaogao")#输出Foo __new__ <class '__main__.Foo'> shuaigaogaoFoo __init__ |
由上面不难看出,大多数情况下,你都不要去重构你的__new__方法,因为你父类中已经有__new__方法了,已经帮你写好了怎么去创建类,如果你重写的话,就会覆盖父类的里面的__new__方法。但是你重构可以增加一点小功能,但是你覆盖了以后还是需要继承父类回来,要不然你的这个实力就创建不了。
3.3 使用场景
我想对我自己写的一些类进行定制,就在它实例化之前就进行定制,就可以用到__new__方法,new方法就是用来创建实力的,重构new方法,必须以返回值的形式继承父类的new方法。
①需求:我在创建对象时候,同时创建一个类变量
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Foo(object): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): #cls相当于是传入的类名Foo cls.name = "shuaigaogao" #创建对象是定义静态变量 print(cls.name) return object.__new__(cls) #继承父类的__new__方法f = Foo("shuaigaogao")print(Foo.name)#输出shuaigaogaoFoo __init__shuaigaogao |
四、__metaclass__方法
4.1 metaclass作用
metaclass这个属性叫做元类,它是用来表示这个类是由谁来帮他实例化创建的,说白了,就是相当于自己定制一个类,就这么一个意思。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
class MyType(type): def __init__(self,*args,**kwargs): print("Mytype __init__",*args,**kwargs) def __call__(self, *args, **kwargs): print("Mytype __call__", *args, **kwargs) obj = self.__new__(self) print("obj ",obj,*args, **kwargs) print(self) self.__init__(obj,*args, **kwargs) return obj def __new__(cls, *args, **kwargs): print("Mytype __new__",*args,**kwargs) return type.__new__(cls, *args, **kwargs)class Foo(object,metaclass=MyType): #python3统一用这种 #__metaclass__ = MyType #python2.7中的写法 def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__",cls, *args, **kwargs) return object.__new__(cls)f = Foo("shuaigaogao")print("f",f)print("fname",f.name)#输出Mytype __new__ Foo (<class 'object'>,) {'__new__': <function Foo.__new__ at 0x0000025EF0EFD6A8>,'__init__': <function Foo.__init__ at 0x0000025EF0EFD620>, '__qualname__': 'Foo', '__module__': '__main__'}Mytype __init__ Foo (<class 'object'>,) {'__new__': <function Foo.__new__ at 0x0000025EF0EFD6A8>, '__init__': <function Foo.__init__ at 0x0000025EF0EFD620>, '__qualname__': 'Foo', '__module__': '__main__'}Mytype __call__ shuaigaogaoFoo __new__ <class '__main__.Foo'>obj <__main__.Foo object at 0x0000025EF0F05048> shuaigaogao<class '__main__.Foo'>Foo __init__f <__main__.Foo object at 0x0000025EF0F05048>fname shuaigaogao |
创建过程如下:

4.2 执行顺序
类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__
metaclass 详解文章:猛击这里 得票最高那个答案写的非常好
面向对象【day08】:类的起源与metaclass(二)的更多相关文章
- 类的起源与metaclass
一.概述 我们知道类可以实例化出对象,那么类本身又是怎么产生的呢?我们就来追溯一下类的起源. 二.类的起源 2.1 创建一个类 class Foo(object): def __init__(self ...
- 谈谈Python中元类Metaclass(二):ORM实践
什么是ORM? ORM的英文全称是“Object Relational Mapping”,即对象-关系映射,从字面上直接理解,就是把“关系”给“对象”化. 对应到数据库,我们知道关系数据库(例如Mys ...
- python中面向对象元类的自定义用法
面向对象中的常用方法 1.instance 和 issubclass instance :判断两个对象是不是一类 issubclass :判断某个类是不是另一个类的子类 #两个常用方法的使用 clas ...
- Java面向对象 Object类 内部类
Java面向对象 Object类 内部类 知识概要: 一:Object类 二:内部类 匿名内部类的写法 1.Object O ...
- 【转】Python之面向对象与类
[转]Python之面向对象与类 本节内容 面向对象的概念 类的封装 类的继承 类的多态 静态方法.类方法 和 属性方法 类的特殊成员方法 继承层级关系中子类的实例对象对属性的查找顺序问题 一.面向对 ...
- python进阶01 面向对象、类、实例、属性封装、实例方法
python进阶01 面向对象.类.实例.属性封装.实例方法 一.面向对象 1.什么是对象 #一切皆对象,可以简单地将“对象”理解为“某个东西” #“对象”之所以称之为对象,是因为它具有属于它自己的“ ...
- python 面向对象与类的基本知识
一 什么是面向对象,面向对象与类的关系. 面向对象的程序设计是用来解决扩展性. 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象 ...
- Python之面向对象元类
Python之面向对象元类 call方法: class People: def __init__(self,name): self.name=name # def __call__(self, *ar ...
- 201871010106-丁宣元 《面向对象程序设计(java)》第十二周学习总结
201871010106-丁宣元 <面向对象程序设计(java)>第十二周学习总结 正文开头: 项目 内容 这个作业属于哪个课程 https://home.cnblogs.com/u/nw ...
随机推荐
- Educational Codeforces Round 53 (Rated for Div. 2) D. Berland Fair
题意:一个人 有T块钱 有一圈商店 分别出售 不同价格的东西 每次经过商店只能买一个 并且如果钱够就必须买 这个人一定是从1号店开始的!(比赛的时候读错了题,以为随意起点...)问可以买多少个 ...
- LOJ2251 [ZJOI2017] 树状数组【线段树】【树套树】
题目分析: 对于一个$add$操作,它的特点是与树状数组的查询相同,会给$1$到它自己产生影响,而$query$操作则会途径所有包含它的树状数组点.现在$add$操作具有前向性(不会影响之后的点).所 ...
- 洛谷3705 [SDOI2017] 新生舞会 【01分数规划】【KM算法】
题目分析: 裸题.怀疑$ O(n^4log{n}) $跑不过,考虑Edmonds-Karp优化. 代码: #include<bits/stdc++.h> using namespace s ...
- Ionic生成的App安装在手机上后无法联网的解决方案
在Ionic中使用inappbrowser.themeablebrowser 组件打开网页,刚开始是好的,后来不知添加什么插件,导致了安装在手机上以后没有网络访问权限. 尝试了很多,最后才发现,此时, ...
- Qt Creator 搭配Git 版本控制
再次介绍一下Git的使用,这次是在Coding.net上部署项目的.这个是写给大作业合作的小伙伴们(我和我的A奶朋友们和某A的男朋友)看的. 安装Git 首先安装Git(msysGit) 下载地址 h ...
- UOJ277【清华集训2016】定向越野(计算几何,最短路)
UOJ题目传送门 显然最优的路径只会经过若干条两个圆的公切线和若干段圆弧 为了方便,把起点终点看成两个半径为\(0\)的圆也行. 最烦的就是算两个圆的公切线了,一共有四条 对于靠外面的两条,我们把切线 ...
- HEOI2016解题报告
树 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记 ...
- [POI2007]ODW-Weights(贪心)
在byteotian公司搬家的时候,他们发现他们的大量的精密砝码的搬运是一件恼人的工作.公司有一些固定容量的容器可以装这些砝码.他们想装尽量多的砝码以便搬运,并且丢弃剩下的砝码.每个容器可以装的砝码数 ...
- 从Java的角度修复文件下载漏洞
从Java的角度谈下文件下载漏洞的产生,然后到他的修复方案.这里我的修复方案是白名单,而没有采用黑名单的方式. 首先先看一段存在文件下载漏洞的代码code: HTML视图页面 download.ht ...
- CodeFroces-- 514.div2.C-Sequence Transformation
题目链接 :514.div2.C-Sequence Transformation #include<bits/stdc++.h> using namespace std; #define ...