目前仍有较多的初学者,或者从其他语言转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__函数相关推荐

  1. python所有函数用法_python函数用法总结

    空函数 如果想定义一个什么事也不做的空函数,可以用pass语句: def nop(): pass pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码 ...

  2. 匿名函数python_基于python内置函数与匿名函数详解

    内置函数 Built-in Functions abs() dict() help() min() setattr() all() dir() hex() next() slice() any() d ...

  3. python命名规则数字开头的成语_浅谈Python中带_的变量或函数命名

    搜索热词 Python 的代码风格由 PEP 8 描述.这个文档描述了 Python 编程风格的方方面面.在遵守这个文档的条件下,不同程序员编写的 Python 代码可以保持最大程度的相似风格.这样就 ...

  4. python匿名函数调用_python之内置函数,匿名函数

    内置函数 我们一起来看看python里的内置函数.什么是内置函数?就是Python给你提供的,拿来直接用的函数,比如print,input等等.截止到python版本3.6.2,现在python一共为 ...

  5. python在匿名函数作和_python内置函数和匿名函数

    楔子 在讲新知识之前,我们先来复习复习函数的基础知识. 问:函数怎么调用? 函数名() 如果你们这么说...那你们就对了!好了记住这个事儿别给忘记了,咱们继续谈下一话题... 来你们在自己的环境里打印 ...

  6. Python内置函数、匿名函数

    内置函数 我们一起来看看python里的内置函数.什么是内置函数?就是Python给你提供的,拿来直接用的函数,比如print,input等等.截止到python版本3.6.2,现在python一共为 ...

  7. python定义一个数据自动去重的函数_110道Python面试题(真题小结)

    该文110道面试题全部来自于大家笔试面试时候拍照后发到群里求助的题目,并自己一道一道亲自做了,大部分题目属于巩固基本python知识点的题目,希望对基本知识不熟悉的同学,能认真做一遍,肯定会有不少收获 ...

  8. python when函数_python help函数

    help()函数是python的一个内置函数 注意: python的内置函数可以直接调用,不需要import导入,它是python自带的函数,任何时候都可以被使用. 一.help()函数的作用 在使用 ...

  9. python语法之元类与type()函数

    元类 千万不要被所谓"元类是99%的python程序员不会用到的特性"这类的说辞吓住.因为每个中国人,都是天生的元类使用者 学懂元类,你只需要知道两句话: 道生一,一生二,二生三, ...

最新文章

  1. Confluence 6 CSS 编辑快速入门
  2. 伪装qizhi software数字签名的下载者分析报告
  3. AtCoder AGC009E Eternal Average (DP)
  4. mysql自动提交 dcl语句_MySQL基础:DCL语句总结
  5. 操作系统学习之用C语言模拟LRU算法
  6. splice方法_JavaScript数组_数组方法【一】(二十六)
  7. C++基本类型隐性转换。
  8. 使用DroidCam过程中所遇到的问题及处理方法
  9. php调用API支付接口 可个人使用,无需营业执照(使用第三方接口,调用的天工接口。)...
  10. Linux 系统中的用户管理
  11. phalcon 自动加载_创建 Phalcon7 项目
  12. 命令 修复损坏的 Ubuntu 系统 ,不用重装
  13. XCTF easyCpp
  14. 基于Java的文本相似度计算
  15. Ubuntu20.04下配置Anaconda3+NVIDIA 驱动+Cuda11.1+Cudnn8.0.5
  16. 原子操作(Atomic)
  17. php后台开发—微信分销那点事
  18. 学习笔记——Git的简单使用
  19. www.starky99.com
  20. 【DIY】树莓派ROS智能小车

热门文章

  1. Java输出语句以及一些占位符在输出语句中的使用
  2. SSL证书问题:无法获取本地颁发者证书
  3. 【微信小程序 三】用户界面
  4. 甲仑榴莲文案:甲仑榴莲水果文案,甲仑榴莲水果促销活动策划文案
  5. Android 动态格子布局(淘宝,京东等首页)
  6. 在抖音APP源码中如何实现播放器的音视频同步
  7. 明明觉醒为啥服务器还在维护,全职觉醒无法连接服务器是什么原因
  8. 操作系统:Win10操作系统内置的备份功能介绍
  9. FineReport报错:删除db.lck
  10. JAVA方法和本地方法