详解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使用mysqldb连接数据库操作方法示例详解
Dec 03 Python
Python入门篇之字典
Oct 17 Python
Python os模块中的isfile()和isdir()函数均返回false问题解决方法
Feb 04 Python
Python pip替换为阿里源的方法步骤
Jul 02 Python
处理python中多线程与多进程中的数据共享问题
Jul 28 Python
python科学计算之narray对象用法
Nov 25 Python
python matplotlib画盒图、子图解决坐标轴标签重叠的问题
Jan 19 Python
Python3.6 + TensorFlow 安装配置图文教程(Windows 64 bit)
Feb 24 Python
python如何提取英语pdf内容并翻译
Mar 03 Python
Python 发送邮件方法总结
Aug 10 Python
Python如何设置指定窗口为前台活动窗口
Aug 12 Python
Python连接Postgres/Mysql/Mongo数据库基本操作大全
Jun 29 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
php随机获取金山词霸每日一句的方法
2015/07/09 PHP
php数组指针操作详解
2017/02/14 PHP
免费空间广告万能消除代码
2006/09/04 Javascript
利用javascript实现禁用网页上所有文本框,下拉菜单,多行文本域
2013/12/14 Javascript
Node.js实现批量去除BOM文件头
2014/12/20 Javascript
jquery Validation表单验证使用详解
2020/09/12 Javascript
jquery SweetAlert插件实现响应式提示框
2015/08/18 Javascript
基于javascript实现全国省市二级联动下拉选择菜单
2016/01/28 Javascript
微信小程序 wxapp导航 navigator详解
2016/10/31 Javascript
微信小程序-获得用户输入内容
2017/02/13 Javascript
浅谈angularjs依赖服务注入写法的注意点
2017/04/24 Javascript
微信分享调用jssdk实例
2017/06/08 Javascript
Easyui使用Dialog行内按钮布局的实例
2017/07/27 Javascript
微信小程序多音频播放进度条问题
2018/08/28 Javascript
一篇文章,教你学会Vue CLI 插件开发
2019/04/17 Javascript
html-webpack-plugin修改页面的title的方法
2020/06/18 Javascript
Vue.js原理分析之nextTick实现详解
2020/09/07 Javascript
python ansible服务及剧本编写
2017/12/29 Python
修改默认的pip版本为对应python2.7的方法
2018/11/06 Python
Python爬虫将爬取的图片写入world文档的方法
2018/11/07 Python
对python多线程与global变量详解
2018/11/09 Python
django多对多表的创建,级联删除及手动创建第三张表
2019/07/25 Python
Python内置函数property()如何使用
2020/09/01 Python
施华洛世奇美国官网:SWAROVSKI美国
2018/02/08 全球购物
意大利自行车商店:Cingolani Bike Shop
2019/09/03 全球购物
北欧最好的童装网上商店:Babyshop
2019/09/15 全球购物
如何用SQL语句进行模糊查找
2015/09/25 面试题
启动一个线程是用run()还是start()
2016/12/25 面试题
网络维护中文求职信
2014/01/03 职场文书
学生会竞聘书范文
2014/03/31 职场文书
网站美工岗位职责
2014/04/02 职场文书
《小猪家的桃花树》教学反思
2014/04/11 职场文书
中国梦演讲稿教师篇
2014/04/23 职场文书
2015年超市员工工作总结
2015/05/04 职场文书
该怎么书写道歉信?
2019/07/03 职场文书
Pytest之测试命名规则的使用
2021/04/16 Python