详解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通过websocket与js客户端通信示例分析
Jun 25 Python
Python操作Excel之xlsx文件
Mar 24 Python
Python使用正则表达式抓取网页图片的方法示例
Apr 21 Python
python实现两个文件合并功能
Apr 01 Python
如何利用Boost.Python实现Python C/C++混合编程详解
Nov 08 Python
对Python 获取类的成员变量及临时变量的方法详解
Jan 22 Python
python七夕浪漫表白源码
Apr 05 Python
python自定义函数实现最大值的输出方法
Jul 09 Python
基于Python爬虫采集天气网实时信息
Jun 05 Python
python 常见的反爬虫策略
Sep 27 Python
Python图片处理之图片裁剪教程
May 27 Python
PyTorch device与cuda.device用法
Apr 03 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
回首过去10年中最搞笑的10部动漫,哪一部让你节操尽碎?
2020/03/03 日漫
PHILIPS D1835/D1875的电路分析与打理
2021/03/02 无线电
PHP和C#可共用的可逆加密算法详解
2015/10/26 PHP
WordPress中转义HTML与过滤链接的相关PHP函数使用解析
2015/12/22 PHP
jquery checkbox,radio是否选中的判断代码
2010/03/20 Javascript
客户端限制只能上传jpg格式图片的js代码
2010/12/09 Javascript
jquery.blockUI.js上传滚动等待效果实现思路及代码
2013/03/18 Javascript
网站404页面3秒后跳到首页的实例代码
2013/08/16 Javascript
jquery实现从数组移除指定的值
2015/06/24 Javascript
JavaScript对象属性检查、增加、删除、访问操作实例
2015/07/08 Javascript
Javascript将双字节字符转换成单字节字符并计算长度
2016/06/22 Javascript
js实现鼠标拖动功能
2017/03/20 Javascript
JS处理数据四舍五入(tofixed与round的区别详解)
2017/10/26 Javascript
JS简单获取并修改input文本框内容的方法示例
2018/04/08 Javascript
推荐一个基于Node.js的表单验证库
2019/02/15 Javascript
微信小程序bindinput与bindsubmit的区别实例分析
2019/04/17 Javascript
vue中通过使用$attrs实现组件之间的数据传递功能
2019/09/01 Javascript
vue动态循环出的多个select出现过的变为disabled(实例代码)
2019/11/10 Javascript
Vue实现鼠标经过文字显示悬浮框效果的示例代码
2020/10/14 Javascript
[01:25:09]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS DT第二场
2014/05/24 DOTA
python访问纯真IP数据库的代码
2011/05/19 Python
Python中datetime常用时间处理方法
2015/06/15 Python
python 用lambda函数替换for循环的方法
2018/06/09 Python
深入浅析Python中list的复制及深拷贝与浅拷贝
2018/09/03 Python
Python 中的lambda函数介绍
2018/10/10 Python
python 实现两个线程交替执行
2020/05/02 Python
Python调用REST API接口的几种方式汇总
2020/10/19 Python
基于HTML5代码实现折叠菜单附源码下载
2015/11/27 HTML / CSS
荷兰时尚精品店:Labels Fashion
2020/03/22 全球购物
应届生求职简历的自我评价怎么写
2013/10/23 职场文书
财务经理的岗位职责
2013/12/17 职场文书
教师自我反思材料
2014/02/14 职场文书
党员群众路线承诺书
2014/05/20 职场文书
商铺门面租房协议书
2014/10/21 职场文书
2016年全国爱眼日宣传教育活动总结
2016/04/05 职场文书
Java8 CompletableFuture 异步回调
2022/04/28 Java/Android