详解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的迭代器和生成器
Jul 29 Python
简单解决Python文件中文编码问题
Nov 22 Python
你应该知道的python列表去重方法
Jan 17 Python
Python表示矩阵的方法分析
May 26 Python
[原创]Python入门教程1. 基本运算【四则运算、变量、math模块等】
Oct 28 Python
对Python中list的倒序索引和切片实例讲解
Nov 15 Python
python障碍式期权定价公式
Jul 19 Python
python3中的eval和exec的区别与联系
Oct 10 Python
使用PyWeChatSpy自动回复微信拍一拍功能的实现代码
Jul 02 Python
使用Python实现音频双通道分离
Dec 25 Python
Python利用socket模块开发简单的端口扫描工具的实现
Jan 27 Python
如何用tempfile库创建python进程中的临时文件
Jan 28 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
PHPMailer安装方法及简单实例
2008/11/25 PHP
phpMyAdmin自动登录和取消自动登录的配置方法
2014/05/12 PHP
推荐5款跨平台的PHP编辑器
2014/12/25 PHP
javascript 火狐(firefox)不显示本地图片问题解决
2008/07/05 Javascript
文本框输入时 实现自动提示(像百度、google一样)
2012/04/05 Javascript
jquery实现图片左右间隔滚动特效(可自动播放)
2013/05/08 Javascript
动态添加option及createElement使用示例
2014/01/26 Javascript
jQuery scrollFix滚动定位插件
2015/04/01 Javascript
javascript实现动态导入js与css等静态资源文件的方法
2015/07/25 Javascript
JS克隆,属性,数组,对象,函数实例分析
2016/11/26 Javascript
微信小程序  TLS 版本必须大于等于1.2问题解决
2017/02/22 Javascript
详解打造 Vue.js 可复用组件
2017/03/24 Javascript
Nodejs 和Session 原理及实战技巧小结
2017/08/25 NodeJs
通过JQuery,JQueryUI和Jsplumb实现拖拽模块
2019/06/18 jQuery
layui表单提交到后台自动封装到实体类的方法
2019/09/12 Javascript
详解Vue之事件处理
2020/07/10 Javascript
vant中的toast轻提示实现代码
2020/11/04 Javascript
JavaScript实现雪花飘落效果
2020/12/27 Javascript
[01:19]DOTA2城市挑战赛报名开始 开启你的城市传奇
2018/03/23 DOTA
python3音乐播放器简单实现代码
2020/04/20 Python
Collatz 序列、逗号代码、字符图网格实例
2017/06/22 Python
Java及python正则表达式详解
2017/12/27 Python
Python语言描述随机梯度下降法
2018/01/04 Python
python实现简单图片物体标注工具
2019/03/18 Python
利用python如何在前程无忧高效投递简历
2019/05/07 Python
pytorch 实现打印模型的参数值
2019/12/30 Python
使用jupyter notebook直接打开.md格式的文件
2020/04/10 Python
龟牌英国商店:Turtle Wax Brand Store UK
2019/07/02 全球购物
Perfume’s Club澳大利亚官网:西班牙领先的在线美容店
2021/02/01 全球购物
问卷调查计划书
2014/01/10 职场文书
岗位竞聘演讲稿
2014/01/10 职场文书
授权委托书(公民个人适用)
2014/09/19 职场文书
化验员岗位职责
2015/02/14 职场文书
汉字听写大会观后感
2015/06/12 职场文书
2016教师暑期培训学习心得体会
2016/01/09 职场文书
2016年学校党支部公开承诺书
2016/03/25 职场文书