Python札记5:__init__函数和__new__函数
目前仍有较多的初学者,或者从其他语言转Python的朋友认为__init__
函数就是Python中类的构造函数,其实是不对的。
Python 2的早期,确实是没有__new__
函数的,但那是很多年前的事情了,现在的Python 2和Python 3中,类实例的创建过程均遵循先调用__new__
函数构造类实例,然后调用__init__
函数对实例进行初始化。
先new再init
看一个简单的例子:
class Sample(object):def __new__(cls):print("Sample.__new__ called")return super().__new__(cls)def __init__(self):print("Sample.__init__ called")s = Sample()
上面的代码会输出:
Sample.__new__ called
Sample.__init__ called
即Python解释器会先调用__new__
函数再调用__init__
函数。
无new不init
上面代码中__new__
函数中调用了父类(object类)的__new__
函数,父类的__new__
函数会创建并返回一个cls
类,也就是Sample
类的实例对象。Sample类的__new__
函数继续返回这个对象。接着这个实例对象被传入__init__
函数,用于初始化该对象中的一些成员。过程如下图所示:
注意:__new__
是静态函数,__init__
是实例函数。
如果,__new__
函数不返回实例对象,那么__init__
函数就不会被调用:
class Sample(object):def __new__(cls):print("Sample.__new__ called")# return super().__new__(cls)def __init__(self):print("Sample.__init__ called")s = Sample()
print(s)
上面的代码会输出:
Sample.__new__ called
None
也就是说,__new__
函数不返回实例对象,那就无法创建类实例。
自定义__new__函数的返回值
如果我们把代码改成这样:
class Sample(object):def __new__(cls):print("Sample.__new__ called")return 666def __init__(self):print("Sample.__init__ called")s = Sample()
print(s)
输出:
Sample.__new__ called
666
可以看到,__new__
函数决定了我们最终创建的是什么类型的对象。这里Sample.__init__
函数没有被调用,因为666是一个int
类型的实例,调用的是int.__init__
函数,这个函数不会输出任何信息。当然,我们还可以返回其他类型的对象,所以__new__
函数给我们带来了很多灵活性。
另外还有一点需要注意,Python规定__init__
函数只能返回None
,否则会引起TypeError
:
class Sample(object):def __new__(cls):print("Sample.__new__ called")return super().__new__(cls)def __init__(self):print("Sample.__init__ called")return 1s = Sample()
输出:
Sample.__new__ called
Sample.__init__ called
Traceback (most recent call last):File "main.py", line 11, in <module>s = Sample()
TypeError: __init__() should return None, not 'int'
单例模式(Singleton)
重写__new__
函数可以带给我们很多灵活性,例如实现单例模式,例如在游戏中同一时刻只允许出现一个大Boss,只有Boss被打死之后,才能新召唤一个Boss:
class Boss(object):_instance = Nonedef __new__(cls):print("Sample.__new__ called")if cls._instance is None:cls._instance = super().__init__(cls)return cls._instancedef __init__(self):print("Sample.__init__ called")boss1 = Boss()
boss2 = Boss()print(id(boss1)) # 140620000188688
print(id(boss2)) # 140620000188688
可以看到boss1和boss2都指向同一个实例。
工厂模式(Factory)
上面我们看到,我们可以自定义__new__
函数的返回值,那么我们可以使用这个特性,实现工厂模式。同样以游戏为例,我们需要一个兵工厂来给我们生产各种类型的战士,例如地精、萨满祭司等等:
class Soldier(object):def __init__(self):passdef attack(self):passdef retreat(self):print("Retreat!!!")class Goblin(Soldier):"""地精"""def __init__(self):passdef attack(self):print("Goblins are attacking!!!")class Shaman(Soldier):"""萨满"""def __init__(self):passdef attack(self):print("Shamans are attacking!!!")class SoldierFactory(object):# 兵工厂能够生产的战士类型soldiers = {'goblin': Goblin, 'shaman': Shaman}def __new__(cls, name):if name in cls.soldiers.keys():return cls.soldiers[name]()return Nonegoblin1 = SoldierFactory("goblin")
goblin2 = SoldierFactory("goblin")
shaman1 = SoldierFactory("shaman")
shaman2 = SoldierFactory("shaman")goblin1.attack() # Goblins are attacking!!!
goblin2.attack() # Goblins are attacking!!!
shaman1.attack() # Shamans are attacking!!!
shaman2.attack() # Shamans are attacking!!!goblin1.retreat() # Retreat!!!
goblin2.retreat() # Retreat!!!
shaman1.retreat() # Retreat!!!
shaman2.retreat() # Retreat!!!
以上就是关于始化函数__init__
和构造函数__new__
的一些简介。
我的知乎:奔三的鑫鑫
欢迎关注微信公众号:小鑫的代码日常
欢迎加入Python学习交流群:532232743,这里有各路高手等着你~
Python札记5:__init__函数和__new__函数相关推荐
- python所有函数用法_python函数用法总结
空函数 如果想定义一个什么事也不做的空函数,可以用pass语句: def nop(): pass pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码 ...
- 匿名函数python_基于python内置函数与匿名函数详解
内置函数 Built-in Functions abs() dict() help() min() setattr() all() dir() hex() next() slice() any() d ...
- python命名规则数字开头的成语_浅谈Python中带_的变量或函数命名
搜索热词 Python 的代码风格由 PEP 8 描述.这个文档描述了 Python 编程风格的方方面面.在遵守这个文档的条件下,不同程序员编写的 Python 代码可以保持最大程度的相似风格.这样就 ...
- python匿名函数调用_python之内置函数,匿名函数
内置函数 我们一起来看看python里的内置函数.什么是内置函数?就是Python给你提供的,拿来直接用的函数,比如print,input等等.截止到python版本3.6.2,现在python一共为 ...
- python在匿名函数作和_python内置函数和匿名函数
楔子 在讲新知识之前,我们先来复习复习函数的基础知识. 问:函数怎么调用? 函数名() 如果你们这么说...那你们就对了!好了记住这个事儿别给忘记了,咱们继续谈下一话题... 来你们在自己的环境里打印 ...
- Python内置函数、匿名函数
内置函数 我们一起来看看python里的内置函数.什么是内置函数?就是Python给你提供的,拿来直接用的函数,比如print,input等等.截止到python版本3.6.2,现在python一共为 ...
- python定义一个数据自动去重的函数_110道Python面试题(真题小结)
该文110道面试题全部来自于大家笔试面试时候拍照后发到群里求助的题目,并自己一道一道亲自做了,大部分题目属于巩固基本python知识点的题目,希望对基本知识不熟悉的同学,能认真做一遍,肯定会有不少收获 ...
- python when函数_python help函数
help()函数是python的一个内置函数 注意: python的内置函数可以直接调用,不需要import导入,它是python自带的函数,任何时候都可以被使用. 一.help()函数的作用 在使用 ...
- python语法之元类与type()函数
元类 千万不要被所谓"元类是99%的python程序员不会用到的特性"这类的说辞吓住.因为每个中国人,都是天生的元类使用者 学懂元类,你只需要知道两句话: 道生一,一生二,二生三, ...
最新文章
- Confluence 6 CSS 编辑快速入门
- 伪装qizhi software数字签名的下载者分析报告
- AtCoder AGC009E Eternal Average (DP)
- mysql自动提交 dcl语句_MySQL基础:DCL语句总结
- 操作系统学习之用C语言模拟LRU算法
- splice方法_JavaScript数组_数组方法【一】(二十六)
- C++基本类型隐性转换。
- 使用DroidCam过程中所遇到的问题及处理方法
- php调用API支付接口 可个人使用,无需营业执照(使用第三方接口,调用的天工接口。)...
- Linux 系统中的用户管理
- phalcon 自动加载_创建 Phalcon7 项目
- 命令 修复损坏的 Ubuntu 系统 ,不用重装
- XCTF easyCpp
- 基于Java的文本相似度计算
- Ubuntu20.04下配置Anaconda3+NVIDIA 驱动+Cuda11.1+Cudnn8.0.5
- 原子操作(Atomic)
- php后台开发—微信分销那点事
- 学习笔记——Git的简单使用
- www.starky99.com
- 【DIY】树莓派ROS智能小车