详解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中if __name__ == &quot;__main__&quot;详细解释
Oct 21 Python
python使用wmi模块获取windows下的系统信息 监控系统
Oct 27 Python
python中字符串类型json操作的注意事项
May 02 Python
Python3.5.3下配置opencv3.2.0的操作方法
Apr 02 Python
python DataFrame 取差集实例
Jan 30 Python
Python中一些深不见底的“坑”
Jun 12 Python
Django 后台获取文件列表 InMemoryUploadedFile的例子
Aug 07 Python
Django之PopUp的具体实现方法
Aug 31 Python
python的scipy实现插值的示例代码
Nov 12 Python
python 安装impala包步骤
Mar 28 Python
使用pandas库对csv文件进行筛选保存
May 25 Python
python脚本框架webpy模板控制结构
Nov 20 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之第二天
2006/10/09 PHP
php使用Smarty的相关注意事项及访问变量的几种方式
2011/12/08 PHP
ini_set的用法介绍
2014/01/07 PHP
php外部执行命令函数用法小结
2016/10/11 PHP
php导出csv文件,可导出前导0实例代码
2016/11/16 PHP
PHP SPL 被遗落的宝石【SPL应用浅析】
2018/04/20 PHP
jQuery的链式调用浅析
2010/12/03 Javascript
js 通用javascript函数库整理
2011/08/14 Javascript
js获取或设置当前窗口url参数的小例子
2013/10/14 Javascript
jquery插件jquery倒计时插件分享
2013/12/27 Javascript
js 调用百度地图api并在地图上进行打点添加标注
2014/05/13 Javascript
js生成的验证码的实现与技术分析
2014/09/17 Javascript
jQuery使用$.each遍历json数组的简单实现方法
2016/04/18 Javascript
jQuery Pagination分页插件使用方法详解
2017/02/28 Javascript
vuex的简单使用教程
2018/02/02 Javascript
解决vue-cli3 使用子目录部署问题
2018/07/19 Javascript
vue-router重写push方法,解决相同路径跳转报错问题
2020/08/07 Javascript
教你安装python Django(图文)
2013/11/04 Python
Win10下Python环境搭建与配置教程
2016/11/18 Python
python生成ppt的方法
2018/06/07 Python
Python3.6日志Logging模块简单用法示例
2018/06/14 Python
Python 十六进制整数与ASCii编码字符串相互转换方法
2018/07/09 Python
解决Pycharm界面的子窗口不见了的问题
2019/01/17 Python
Python3使用 GitLab API 进行批量合并分支
2020/10/15 Python
鲜为人知的HTML5语音合成功能
2019/05/17 HTML / CSS
HTML中使用SVG与SVG预定义形状元素介绍
2013/06/28 HTML / CSS
canvas 基础之图像处理的使用
2020/04/10 HTML / CSS
同步和异步有何异同,在什么情况下分别使用他们?举例说明
2014/02/27 面试题
市场营销专业推荐信
2013/11/03 职场文书
初中校园广播稿
2014/02/02 职场文书
老人祝寿主持词
2014/03/28 职场文书
幼儿园毕业寄语
2014/04/03 职场文书
酒店管理专业自荐信
2014/05/23 职场文书
子女赡养老人协议书
2016/03/23 职场文书
员工升职自我评价
2019/03/26 职场文书
python生成可执行exe控制Microsip自动填写号码并拨打功能
2021/06/21 Python