详解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类:class创建、数据方法属性及访问控制详解
Jul 25 Python
numpy使用技巧之数组过滤实例代码
Feb 03 Python
使用Python读取大文件的方法
Feb 11 Python
python使用筛选法计算小于给定数字的所有素数
Mar 19 Python
Python 2.7中文显示与处理方法
Jul 16 Python
selenium获取当前页面的url、源码、title的方法
Jun 12 Python
Python模块汇总(常用第三方库)
Oct 07 Python
python GUI库图形界面开发之PyQt5拖放控件实例详解
Feb 25 Python
构建高效的python requests长连接池详解
May 02 Python
python中的测试框架
Nov 13 Python
python 下划线的多种应用场景总结
May 12 Python
Pyqt5将多个类组合在一个界面显示的完整示例
Sep 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
定制404错误页面,并发信给管理员的程序
2006/10/09 PHP
php网站被挂木马后的修复方法总结
2014/11/06 PHP
PHP生成可点击刷新的验证码简单示例
2016/05/13 PHP
PDO::getAvailableDrivers讲解
2019/01/28 PHP
添加JavaScript重载函数的辅助方法2
2010/07/04 Javascript
基于jQuery实现的Ajax 验证用户名是否存在的实现代码
2011/04/06 Javascript
JS验证控制输入中英文字节长度(input、textarea等)具体实例
2013/06/21 Javascript
JavaScript将数据转换成整数的方法
2014/01/04 Javascript
Jquery实现点击按钮,连续地向textarea中添加值的实例代码
2014/03/08 Javascript
jQuery 中的 DOM 操作
2016/04/26 Javascript
Easyui 之 Treegrid 笔记
2016/04/29 Javascript
深入分析javascript中的错误处理机制
2016/07/17 Javascript
Vue计算属性的学习笔记
2017/03/22 Javascript
详解JS中的this、apply、call、bind(经典面试题)
2017/09/19 Javascript
详解使用uni-app开发微信小程序之登录模块
2019/05/09 Javascript
Python multiprocessing.Manager介绍和实例(进程间共享数据)
2014/11/21 Python
python多进程共享变量
2016/04/06 Python
win10环境下python3.5安装步骤图文教程
2017/02/03 Python
对python 中class与变量的使用方法详解
2019/06/26 Python
Python 操作mysql数据库查询之fetchone(), fetchmany(), fetchall()用法示例
2019/10/17 Python
python 循环数据赋值实例
2019/12/02 Python
python开发前景如何
2020/06/11 Python
python简单利用字典破解zip文件口令
2020/09/07 Python
Python爬虫爬取微博热搜保存为 Markdown 文件的源码
2021/02/22 Python
美国最大的旗帜经销商:Carrot-Top
2018/02/26 全球购物
大专会计自我鉴定
2014/02/06 职场文书
出纳会计岗位职责
2014/03/12 职场文书
西式结婚主持词
2014/03/14 职场文书
企业授权委托书范本
2014/04/02 职场文书
老龄工作先进事迹
2014/08/15 职场文书
2014校长四风问题对照检查材料思想汇报
2014/09/16 职场文书
2015年圣诞节寄语
2015/08/17 职场文书
学生会副主席竞选稿
2015/11/19 职场文书
Python初识逻辑与if语句及用法大全
2021/08/07 Python
关于springboot配置druid数据源不生效问题(踩坑记)
2021/09/25 Java/Android
剑指Offer之Java算法习题精讲二叉树专项训练
2022/03/21 Java/Android