详解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中实现php的var_dump函数功能
Jan 21 Python
如何将python中的List转化成dictionary
Aug 15 Python
Python文件与文件夹常见基本操作总结
Sep 19 Python
python爬虫入门教程--HTML文本的解析库BeautifulSoup(四)
May 25 Python
python构建深度神经网络(DNN)
Mar 10 Python
利用Python如何将数据写到CSV文件中
Jun 05 Python
Python3爬虫学习之应对网站反爬虫机制的方法分析
Dec 12 Python
Python3调用百度AI识别图片中的文字功能示例【测试可用】
Mar 13 Python
Python目录和文件处理总结详解
Sep 02 Python
Ubuntu下Python+Flask分分钟搭建自己的服务器教程
Nov 19 Python
基于python中__add__函数的用法
Nov 25 Python
tensorflow 动态获取 BatchSzie 的大小实例
Jun 30 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简单系统查询模块代码打包下载
2008/06/07 PHP
PHP 事件机制(2)
2011/03/23 PHP
php数组函数序列 之shuffle()和array_rand() 随机函数使用介绍
2011/10/29 PHP
php标签云的实现代码
2012/10/10 PHP
深入解析PHP 5.3.x 的strtotime() 时区设定 警告信息修复
2013/08/05 PHP
PHP计算加权平均数的方法
2015/07/16 PHP
Javascript 中 null、NaN和undefined的区别总结
2013/04/10 Javascript
关于在IE下的一个安全BUG --可用于跟踪用户的系统鼠标位置
2013/04/17 Javascript
解析js原生方法创建表格效率测试
2013/07/08 Javascript
100个不能错过的实用JS自定义函数
2014/03/05 Javascript
JavaScript包装对象使用详解
2015/07/09 Javascript
jQuery编程中的一些核心方法简介
2015/08/14 Javascript
Sublime Text 3常用插件及安装方法
2015/12/16 Javascript
浏览器检测JS代码(兼容目前各大主流浏览器)
2016/02/21 Javascript
jQuery实现遍历复选框的方法示例
2017/03/06 Javascript
如何手动实现es5中的bind方法详解
2018/12/07 Javascript
JavaScript使用ul中li标签实现删除效果
2019/04/15 Javascript
JS匿名函数内部this指向问题详析
2019/05/10 Javascript
Linux 下 Python 实现按任意键退出的实现方法
2016/09/25 Python
一篇文章读懂Python赋值与拷贝
2018/04/19 Python
Python实现重建二叉树的三种方法详解
2018/06/23 Python
Python日期时间模块datetime详解与Python 日期时间的比较,计算实例代码
2018/09/14 Python
Tornado实现多进程/多线程的HTTP服务详解
2019/07/25 Python
使用OpenCV-python3实现滑动条更新图像的Canny边缘检测功能
2019/12/12 Python
中国高端鲜花第一品牌:roseonly(一生只送一人)
2017/02/12 全球购物
英国排名第一的停车场运营商:NCP
2019/08/26 全球购物
设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。
2014/12/30 面试题
如何从一个文件档案的尾端新增记录
2016/12/02 面试题
学生处主任岗位职责
2013/12/01 职场文书
简历中自我评价怎么写
2014/02/12 职场文书
医院竞聘演讲稿
2014/05/16 职场文书
课程设计的心得体会
2014/09/03 职场文书
2014年科研工作总结
2014/12/03 职场文书
学校中层领导培训心得体会
2016/01/11 职场文书
小学2016年第十八届推普周活动总结
2016/04/05 职场文书
Windows server 2012 NTP时间同步的实现
2022/06/25 Servers