详解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 除法小技巧
Sep 06 Python
跟老齐学Python之编写类之一创建实例
Oct 11 Python
使用Python中的cookielib模拟登录网站
Apr 09 Python
详细介绍Ruby中的正则表达式
Apr 10 Python
Python 递归函数详解及实例
Dec 27 Python
Python3 安装PyQt5及exe打包图文教程
Jan 08 Python
Python时间和字符串转换操作实例分析
Mar 16 Python
对YOLOv3模型调用时候的python接口详解
Aug 26 Python
Python ORM框架Peewee用法详解
Apr 29 Python
python+openCV对视频进行截取的实现
Nov 27 Python
python字典与json转换的方法总结
Dec 28 Python
pygame面向对象的飞行小鸟实现(Flappy bird)
Apr 01 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 文件上传类代码
2011/08/06 PHP
PHP输出XML到页面的3种方法详解
2013/06/06 PHP
PHP排序算法之基数排序(Radix Sort)实例详解
2018/04/21 PHP
PHP下载文件函数与用法示例
2019/09/27 PHP
PHP使用PDO实现mysql防注入功能详解
2019/12/20 PHP
javaScript矢量图表库-gRaphael几行代码实现精美的条形图/饼图/点图/曲线图
2013/01/09 Javascript
JQuery for与each性能比较分析
2013/05/14 Javascript
浏览器的JavaScript引擎的识别方法
2013/10/20 Javascript
JS JSON对象转为字符串的简单实现方法
2013/11/18 Javascript
javascript用函数实现对象的方法
2015/05/14 Javascript
超漂亮的jQuery图片轮播特效
2015/11/24 Javascript
详解jQuery中的empty、remove和detach
2016/04/11 Javascript
JS瀑布流实现方法实例分析
2016/12/19 Javascript
JavaScript仿微信(电话)联系人列表滑动字母索引实例讲解(推荐)
2017/08/16 Javascript
微信小程序模拟cookie的实现
2018/06/20 Javascript
JavaScript数组去重的方法总结【12种方法,号称史上最全】
2019/02/28 Javascript
vue中datepicker的使用教程实例代码详解
2019/07/08 Javascript
nodejs对mongodb数据库的增加修删该查实例代码
2020/01/05 NodeJs
基于vue的tab-list类目切换商品列表组件的示例代码
2020/02/14 Javascript
javascript递归函数定义和用法示例分析
2020/07/22 Javascript
[01:32:50]DOTA2-DPC中国联赛 正赛 DLG vs XG BO3 第一场 1月25日
2021/03/11 DOTA
轻松掌握python设计模式之访问者模式
2016/11/18 Python
python中比较两个列表的实例方法
2019/07/04 Python
Python任务调度利器之APScheduler详解
2020/04/02 Python
python简单实现9宫格图片实例
2020/09/03 Python
pandas 数据类型转换的实现
2020/12/29 Python
纯CSS3单页切换导航菜单界面设计的简单实现
2016/08/16 HTML / CSS
CSS3 :default伪类选择器使用简介
2018/03/15 HTML / CSS
Html5页面点击遮罩层背景关闭遮罩层
2020/11/30 HTML / CSS
木马的传播途径主要有哪些
2016/04/08 面试题
2014年国庆标语
2014/06/30 职场文书
小学生2014国庆节演讲稿:祖国在我心中
2014/09/21 职场文书
欢送会主持词
2015/07/01 职场文书
信息技术远程培训心得体会
2016/01/09 职场文书
对象析构函数__del__在Python中何时使用
2022/03/22 Python
大型强子对撞机再次重启探索“第五种自然力”
2022/04/29 数码科技