06 __init__ 和 __new__的关系和不同
一、 双下new 和 双下init 关系
首先从__new__(cls,a,b,c)的参数说说起,__new__方法的第一个参数是这个类,而其余的参数会在调用成功后全部传递给__init__方法初始化,
所以,__new__方法先于__init__方法执行:
class A:
pass class B(A):
def __new__(cls):
print("__new__方法被执行")
return super().__new__(cls) def __init__(self):
print("__init__方法被执行") b = B()
#先执行new再执行init __new__方法被执行
__init__方法被执行
我们比较两个方法的参数,
可以发现__new__方法是传入类(cls),而__init__方法传入类产生的对象(self),
当你要创建类的对象时,会首先执行元类中的__new__方法,它返回一个空的实例化对象,然后会将该对象自动传给__init__来对这个类进行初始化操作填充属性,
如果new不返回,即返回值为None那么init将不会执行
通常我们定义类的时候只写__init__,来初始化对象,并不是没用__new__,只是内部调用了元类(如:type)的而已,不信你可以手动创建一个new覆盖父类的new,pass掉不返回任何,执行代码会报错,new不工作init就根本不会执行,根本不能实例化出对象
注意:,如果你覆盖了父类的new方法,那么必须保证你的new方法必须有返回值,且必须是对应的类对象,否则init不能工作
二、new的强大之处
我们可以这么理解它们之间的关系,__new__是开辟疆域的大将军,而__init__是在这片疆域上辛勤劳作的小老百姓,只有__new__执行完后,开辟好疆域后,__init__才能工作。
绝大多数情况下,我们都不需要自己重写__new__方法,但在当继承一个不可变的类型(例如str类,int类等)时,它的特性就尤显重要了
可以在我的自定义元类里面定义一个__new__方法,看看它到底是个啥
class Mymeta(type):
def __new__(cls, *args, **kwargs):
print(cls)
print(args)
print(kwargs)
return type.__new__(cls,*args,**kwargs) class OldboyTeacher(object,metaclass=Mymeta):
school = 'oldboy'
def __init__(self, name):
self.name = name def run(self):
print('%s is running' % self.name) """
<class '__main__.Mymeta'>
('OldboyTeacher', (object,), {'__module__': '__main__', '__qualname__': 'OldboyTeacher', 'school': 'oldboy', '__init__': <function OldboyTeacher.__init__ at 0x000000323CEB9510>, 'run': <function OldboyTeacher.run at 0x000000323CEE7158>})
{}
"""
new参数详解
我们发现__new__里面的*args参数接收到了三个位置参数,并且很容易辨认它们对应的就是类名,类的父类,类体代码执行后的名称空间
那么我们可不可以将__new__()的形参换一种写法:
例子1:
class Mymeta(type):
def __new__(cls, class_name,class_bases,class_dic):
class_dic['xxx'] = ''
if 'school' in class_dic:
class_dic['school'] = 'DSB'
return type.__new__(cls,class_name,class_bases,class_dic) class OldboyTeacher(metaclass=Mymeta):
school = 'oldboy'
def __init__(self,name):
self.name = name
def run(self):
print('%s is running'%self.name) print(OldboyTeacher.xxx) # 发现可以打印出来 123
print(OldboyTeacher.school) # DSB
'''
注意;
如果把__new__换成__init__
打印xxx属性会报错,找不到
打印school属性,结果是oldboy而不是DSB
new可以重新开辟内存空间,新增属性、修改属性,init不行
'''
我们知道字符串是不可改变的,所以使用__init__,传入的字符串相当于已经被打下的疆域,而这块疆域除了将军其他谁也无法改变,__init__只能在这块领地上干瞪眼,此时这块疆域就是”oldboy“。
而使用__new__,相当于__new__大将军自己干活,重新去开辟了一块疆域,所以疆域上的内容可以发生变化,此时这块疆域变成了'123','DSB'。
例子2:
class CapStr(str):
def __init__(self, string):
string = string.upper() a = CapStr("I love China!")
print(a)
"""
I love China!
"""
class CapStr(str):
def __new__(cls, string):
string = string.upper()
return super().__new__(cls, string) a = CapStr("I love China!")
print(a)
"""
I LOVE CHINA!
"""
传入的字符串相当于已经被打下的疆域,而这块疆域除了将军其他谁也无法改变,__init__只能在这块领地上干瞪眼,此时这块疆域就是”I love China!“。而第二个例子中,__new__大将军重新去开辟了一块疆域,所以疆域上的内容也发生了变化,此时这块疆域变成了”I LOVE CHINA!“
结论:
我们可以通过自定义元类,并重写__new__方法来拦截类的创建过程,在类被创建出来之前进行一系列其他操作,实现类一创建出来就自带buff
new方法和init 都可以实现控制类的创建过程,init更简单,但是new功能强大
06 __init__ 和 __new__的关系和不同的更多相关文章
- Python中的__init__和__new__
一.__init__ 方法是什么? 使用Python写过面向对象的代码的同学,可能对 __init__ 方法已经非常熟悉了,__init__ 方法通常用在初始化一个类实例的时候.例如: # -*- c ...
- python中的__init__和__new__的区别
一.__init__ 方法是什么?(init前后的线是双下划线) 使用Python写过面向对象的代码的同学,可能对 __init__ 方法已经非常熟悉了,__init__ 方法通常用在初始化一个类实例 ...
- Python中__init__和__new__的区别详解
__init__ 方法是什么? 使用Python写过面向对象的代码的同学,可能对 __init__ 方法已经非常熟悉了,__init__ 方法通常用在初始化一个类实例的时候.例如: # -*- cod ...
- 详解Python中的__init__和__new__(静态方法)
一.__init__ 方法是什么? 使用Python写过面向对象的代码的同学,可能对 __init__ 方法已经非常熟悉了,__init__ 方法通常用在初始化一个类实例的时候.例如: #-*- co ...
- 详解Python中的__init__和__new__
转载:https://my.oschina.net/liuyuantao/blog/747164 1.__init__ 方法是什么? 使用Python写过面向对象的代码的同学,可能对 __init__ ...
- python中的__init__ 、__new__、__call__小结
这篇文章主要介绍了python中的__init__ .__new__.__call__小结,需要的朋友可以参考下 1.__new__(cls, *args, **kwargs) 创建对象时调用,返回 ...
- 详解python中的__init__与__new__方法
一.__init__和__new__方法执行的顺序? 在面向对象中介绍了关于对象创建的过程,我们知道__new__方法先于__init__方法执行. 二.__new__方法是什么? 首先,我们先来看下 ...
- 简析 __init__、__new__、__call__ 方法
简析 __init__.__new__.__call__ 方法 任何事物都有一个从创建,被使用,再到消亡的过程,在程序语言面向对象编程模型中,对象也有相似的命运:创建.初始化.使 用.垃圾回收,不同的 ...
- python 的__init__ 和__new__ 区别
在此介绍一下 __init__ 和 __new__ 先后调用的区别 代码如下: # __init__ 和 __new__的区别 # 通常在编代码时,__init__ 较为常见,但是__new__却 ...
随机推荐
- python3(四十)datetime timestamp str
"""时间处理 """ __author__on__ = 'shaozhiqi 2019/9/25' # !/usr/bin/env pyt ...
- Idea离线安装plugins插件 如Lombok
由于公司不允许使用外网,之前用的idea 15 安装了一次.但是idea15的提示不够友好,今天升级idea2017.3.2,同样又需要安装,那就写个教程吧. 网上其他的安装教程不通用,也是针对不同i ...
- 树状数组模板--Color the ball
Color the ball HDU - 1556 N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电 ...
- Linux c++ vim环境搭建系列(1)——Ubuntu18.04.4编译安装vim8.2
1. vim源码编译安装 参考网址: https://github.com/ycm-core/YouCompleteMe/wiki/Building-Vim-from-source 安装各类依赖库 s ...
- 搭建WEB、NFS共享、sersync实时同步以及全网定时备份服务流程
本次实验的主要目的: 1.搭建web服务,使用nfs服务共享的/data目录挂载到web站点目录上. 2.nfs服务器与backup服务器使用sersync实时同步/data目录中的文件. 3.bac ...
- AJ学IOS 之微博项目实战(6)导航控制器NavigationController 的滑动回退功能实现
AJ分享,必须精品 一:效果 第二篇里面写了怎样自定义navigation实现自定义的导航控制器左右按钮样式,但是当我们自己实现后,系统自带的向右边滑动来实现回退的功能就不能用了. 这里主要实现滑动回 ...
- JMF 下载安装与测试 测试成功
本来就是想在自己写的java里面加入实习的摄像头监控,然后个各种百度了一下,就用JMF来弄了,不过这个东西貌似比较旧,网上的资料虽然说有,但是也不是太多,并且遇到的一下问题也不能解决,总之经过了一天的 ...
- python批量添加hexo文章封面
❝ 本文需要工具: 「excel」 「python3.x」 ❞ 今天突然觉得,我的博客的文章更新这么多了竟然还没有一个封面,觉得首页相当低调了- 首页 正好皮肤带有文章封面功能,所以我觉得要将文章批量 ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(二)之Introduction to Objects
The genesis of the computer revolution was a machine. The genesis of out programming languages thus ...
- Docker搭建Nessus pro笔记
0x01 准备Docker环境 拉取镜像: docker pull ubuntu 创建容器: docker run -p 9922:22 -p 8834:8834 --name nessus -it ...