详解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之玩转字符串(3)
Sep 14 Python
跟老齐学Python之模块的加载
Oct 24 Python
解析Python中的__getitem__专有方法
Jun 27 Python
python实现各进制转换的总结大全
Jun 18 Python
PyQt5每天必学之布局管理
Apr 19 Python
python实现旋转和水平翻转的方法
Oct 25 Python
python实现在遍历列表时,直接对dict元素增加字段的方法
Jan 15 Python
Python直接赋值、浅拷贝与深度拷贝实例分析
Jun 18 Python
Tensorflow 多线程与多进程数据加载实例
Feb 05 Python
keras slice layer 层实现方式
Jun 11 Python
python中的None与NULL用法说明
May 25 Python
Python内置数据结构列表与元组示例详解
Aug 04 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
使用网络地址转换实现多服务器负载均衡
2006/10/09 PHP
PHP实现下载断点续传的方法
2014/11/12 PHP
php 参数过滤、数据过滤详解
2015/10/26 PHP
PHP代码重构方法漫谈
2018/04/17 PHP
PHP7匿名类的用法示例
2019/04/05 PHP
js几个不错的函数 $$()
2006/10/09 Javascript
js实现双击图片放大单击缩小的方法
2015/02/17 Javascript
1秒50万字!js实现关键词匹配
2016/08/01 Javascript
js实现HashTable(哈希表)的实例分析
2016/11/21 Javascript
jQuery生成假加载动画效果
2016/12/01 Javascript
COM组件中调用JavaScript函数详解及实例
2017/02/23 Javascript
layui弹出层效果实现代码
2017/05/19 Javascript
js实现每日签到功能
2018/11/29 Javascript
vue 详情跳转至列表页实现列表页缓存
2019/03/27 Javascript
Vue的click事件防抖和节流处理详解
2019/11/13 Javascript
javascript实现点击星星小游戏
2019/12/24 Javascript
jQuery实现鼠标放置名字上显示详细内容气泡提示框效果的方法分析
2020/04/04 jQuery
vue 需求 data中的数据之间的调用操作
2020/08/05 Javascript
Zabbix实现微信报警功能
2016/10/09 Python
深入理解Python3 内置函数大全
2017/11/23 Python
Django中间件工作流程及写法实例代码
2018/02/06 Python
Python实现统计给定字符串中重复模式最高子串功能示例
2018/05/16 Python
PyTorch的Optimizer训练工具的实现
2019/08/18 Python
Python拆分大型CSV文件代码实例
2019/10/07 Python
详解python中groupby函数通俗易懂
2020/05/14 Python
Python如何读取、写入CSV数据
2020/07/28 Python
Perfume’s Club法国站:购买香水和化妆品
2019/05/02 全球购物
华为消费者德国官方网站:HUAWEI德国
2020/11/03 全球购物
应届生程序员求职信
2013/11/05 职场文书
工程造价与管理专业应届生求职信
2013/11/23 职场文书
2014年秋季开学典礼主持词
2014/08/02 职场文书
原告代理词范文
2015/05/25 职场文书
2019个人工作自我评价范文(3篇)
2019/09/19 职场文书
解决Django transaction进行事务管理踩过的坑
2021/04/24 Python
Python中使用subprocess库创建附加进程
2021/05/11 Python
MySQL通过binlog恢复数据
2021/05/27 MySQL