详解Python中的__new__、__init__、__call__三个特殊方法


Posted in Python onJune 02, 2016

__new__: 对象的创建,是一个静态方法,第一个参数是cls。(想想也是,不可能是self,对象还没创建,哪来的self)
__init__ : 对象的初始化, 是一个实例方法,第一个参数是self。
__call__ : 对象可call,注意不是类,是对象。

先有创建,才有初始化。即先__new__,而后__init__。
上面说的不好理解,看例子。

1.对于__new__

class Bar(object): 
  pass 
 
class Foo(object): 
  def __new__(cls, *args, **kwargs): 
    return Bar() 
 
print Foo()

 可以看到,输出来是一个Bar对象。

__new__方法在类定义中不是必须写的,如果没定义,默认会调用object.__new__去创建一个对象。如果定义了,就是override,可以custom创建对象的行为。
聪明的读者可能想到,既然__new__可以custom对象的创建,那我在这里做一下手脚,每次创建对象都返回同一个,那不就是单例模式了吗?没错,就是这样。可以观摩《飘逸的python - 单例模式乱弹》
定义单例模式时,因为自定义的__new__重载了父类的__new__,所以要自己显式调用父类的__new__,即object.__new__(cls, *args, **kwargs),或者用super()。,不然就不是extend原来的实例了,而是替换原来的实例。

2.对于__init__

使用Python写过面向对象的代码的同学,可能对 __init__ 方法已经非常熟悉了,__init__ 方法通常用在初始化一个类实例的时候。例如:

# -*- coding: utf-8 -*-

class Person(object):
  """Silly Person"""

  def __init__(self, name, age):
    self.name = name
    self.age = age

  def __str__(self):
    return '<Person: %s(%s)>' % (self.name, self.age)

if __name__ == '__main__':
  piglei = Person('piglei', 24)
  print piglei

这样便是__init__最普通的用法了。但__init__其实不是实例化一个类的时候第一个被调用 的方法。当使用 Persion(name, age) 这样的表达式来实例化一个类时,最先被调用的方法 其实是 __new__ 方法。

3.对于__call__
对象通过提供__call__(slef, [,*args [,**kwargs]])方法可以模拟函数的行为,如果一个对象x提供了该方法,就可以像函数一样使用它,也就是说x(arg1, arg2...) 等同于调用x.__call__(self, arg1, arg2) 。模拟函数的对象可以用于创建防函数(functor) 或代理(proxy).

class Foo(object): 
  def __call__(self): 
    pass 
 
f = Foo()#类Foo可call 
f()#对象f可call

总结,在Python中,类的行为就是这样,__new__、__init__、__call__等方法不是必须写的,会默认调用,如果自己定义了,就是override,可以custom。既然override了,通常也会显式调用进行补偿以达到extend的目的。
这也是为什么会出现"明明定义def _init__(self, *args, **kwargs),对象怎么不进行初始化"这种看起来诡异的行为。(注,这里_init__少写了个下划线,因为__init__不是必须写的,所以这里不会报错,而是当做一个新的方法_init__)

Python 相关文章推荐
从零学python系列之浅谈pickle模块封装和拆封数据对象的方法
May 23 Python
Python pickle模块用法实例
Apr 14 Python
python通过get,post方式发送http请求和接收http响应的方法
May 26 Python
30秒轻松实现TensorFlow物体检测
Mar 14 Python
用python写扫雷游戏实例代码分享
May 27 Python
Pyinstaller打包.py生成.exe的方法和报错总结
Apr 02 Python
python pyinstaller 加载ui路径方法
Jun 10 Python
python操作文件的参数整理
Jun 11 Python
Python封装成可带参数的EXE安装包实例
Aug 24 Python
使用pandas的box_plot去除异常值
Dec 10 Python
python2.7使用scapy发送syn实例
May 05 Python
Python实现JS解密并爬取某音漫客网站
Oct 23 Python
Python实现优先级队列结构的方法详解
Jun 02 #Python
KMP算法精解及其Python版的代码示例
Jun 01 #Python
Python缩进和冒号详解
Jun 01 #Python
Python注释详解
Jun 01 #Python
深入理解python try异常处理机制
Jun 01 #Python
python学习 流程控制语句详解
Jun 01 #Python
python+Django+apache的配置方法详解
Jun 01 #Python
You might like
ThinkPHP中I(),U(),$this-&gt;post()等函数用法
2014/11/22 PHP
thinkPHP批量删除的实现方法分析
2016/11/09 PHP
Yii CFileCache 获取不到值的原因分析
2017/02/08 PHP
javascript css在IE和Firefox中区别分析
2009/02/18 Javascript
40个有创意的jQuery图片和内容滑动及弹出插件收藏集之二
2011/12/31 Javascript
8款非常棒的响应式jQuery 幻灯片插件推荐
2012/02/02 Javascript
javascrip关于继承的小例子
2013/05/10 Javascript
利用JS进行图片的切换即特效展示图片
2013/12/03 Javascript
jquery 使用简明教程
2014/03/05 Javascript
JavaScript判断用户是否对表单进行了修改的方法
2015/03/18 Javascript
javascript中几个容易混淆的概念总结
2015/04/14 Javascript
ionic 上拉菜单(ActionSheet)实例代码
2016/06/06 Javascript
JavaScript中的普通函数和箭头函数的区别和用法详解
2017/03/21 Javascript
基于JavaScript实现的希尔排序算法分析
2017/04/14 Javascript
微信小程序获取循环元素id以及wx.login登录操作
2017/08/17 Javascript
XMLHttpRequest对象_Ajax异步请求重点(推荐)
2017/09/28 Javascript
微信小程序App生命周期详解
2018/01/31 Javascript
Vue组件创建和传值的方法
2018/08/17 Javascript
es6数值的扩展方法
2019/03/11 Javascript
解决antd 下拉框 input [defaultValue] 的值的问题
2020/10/31 Javascript
关于element的表单组件整理笔记
2021/02/05 Javascript
k8s node节点重新加入master集群的实现
2021/02/22 Javascript
[43:53]OG vs EG 2019国际邀请赛淘汰赛 胜者组 BO3 第三场 8.22
2019/09/05 DOTA
Python函数学习笔记
2008/10/07 Python
分析在Python中何种情况下需要使用断言
2015/04/01 Python
python中numpy.zeros(np.zeros)的使用方法
2017/11/07 Python
使用python判断你是青少年还是老年人
2018/11/29 Python
使用Django清空数据库并重新生成
2020/04/03 Python
Python自动化测试中yaml文件读取操作
2020/08/20 Python
高档奢华时装在线目的地:FORWARD by elyse walker
2017/10/16 全球购物
在数据文件自动增长时,自动增长是否会阻塞对文件的更新
2014/05/01 面试题
委托协议书范本
2014/04/22 职场文书
大学生新学期计划书
2014/04/28 职场文书
说好普通话圆梦你我他演讲稿
2014/09/21 职场文书
教师节班会主持词
2015/07/06 职场文书
年终工作总结范文
2019/06/20 职场文书