详解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中的 is 操作符
Dec 26 Python
python实现员工管理系统
Jan 11 Python
python实现树形打印目录结构
Mar 29 Python
python 获取指定文件夹下所有文件名称并写入列表的实例
Apr 23 Python
python tkinter窗口最大化的实现
Jul 15 Python
Python Selenium 之数据驱动测试的实现
Aug 01 Python
PyCharm专业最新版2019.1安装步骤(含激活码)
Oct 09 Python
Python读入mnist二进制图像文件并显示实例
Apr 24 Python
Python实现图片查找轮廓、多边形拟合、最小外接矩形代码
Jul 14 Python
Pycharm创建文件时自动生成文件头注释(自定义设置作者日期)
Nov 24 Python
python 实现网易邮箱邮件阅读和删除的辅助小脚本
Mar 01 Python
使用Python快速打开一个百万行级别的超大Excel文件的方法
Mar 02 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异常处理技术,顶级异常处理器
2012/06/13 PHP
apache php模块整合操作指南
2012/11/16 PHP
php实现zip压缩文件解压缩代码分享(简单易懂)
2014/05/10 PHP
php实现的Captcha验证码类实例
2014/09/22 PHP
PHP中$this和$that指针使用实例
2015/01/06 PHP
PHP批量删除jQuery操作
2017/07/23 PHP
Jquery异步请求数据实例代码
2011/12/28 Javascript
js身份证判断方法支持15位和18位
2014/03/18 Javascript
JavaScript避免内存泄露及内存管理技巧
2014/09/05 Javascript
JS实现兼容性较好的随屏滚动效果
2015/11/09 Javascript
jQuery zTree加载树形菜单功能
2016/02/25 Javascript
Vue.js原理分析之observer模块详解
2017/02/17 Javascript
详解webpack进阶之插件篇
2017/07/06 Javascript
angularjs实现table增加tr的方法
2018/02/27 Javascript
在NPM发布自己造的轮子的方法步骤
2019/03/09 Javascript
jQuery+PHP+Ajax实现动态数字统计展示功能
2019/12/25 jQuery
JS sort方法基于数组对象属性值排序
2020/07/10 Javascript
js canvas实现五子棋小游戏
2021/01/22 Javascript
Python读取图片EXIF信息类库介绍和使用实例
2014/07/10 Python
python批量提交沙箱问题实例
2014/10/08 Python
python实现员工管理系统
2018/01/11 Python
python解析json串与正则匹配对比方法
2018/12/20 Python
Python进阶之全面解读高级特性之切片
2019/02/19 Python
Python实现封装打包自己写的代码,被python import
2020/07/12 Python
请介绍一下Ant
2016/07/22 面试题
上海方立数码笔试题
2013/10/18 面试题
实现向右循环移位
2014/07/31 面试题
电气自动化自荐信
2013/10/10 职场文书
普罗米修斯教学反思
2014/02/06 职场文书
学生会招新策划书
2014/02/14 职场文书
经济信息系毕业生自荐信
2014/06/02 职场文书
党员反对四风问题思想汇报
2014/09/12 职场文书
男生贾里读书笔记
2015/06/30 职场文书
儿子满月酒致辞
2015/07/29 职场文书
德劲DE1107指针试高灵敏度全波段收音机机评
2022/04/05 无线电
Windows Server 版本 20H2 于 8 月 9 日停止支持,Win10 版本 21H1 将于 12 月结束支
2022/07/23 数码科技