详解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 相关文章推荐
在Django的URLconf中使用多个视图前缀的方法
Jul 18 Python
python中使用序列的方法
Aug 03 Python
Python查找第n个子串的技巧分享
Jun 27 Python
Python 2.7中文显示与处理方法
Jul 16 Python
对python的bytes类型数据split分割切片方法
Dec 04 Python
python 使用matplotlib 实现从文件中读取x,y坐标的可视化方法
Jul 04 Python
python防止随意修改类属性的实现方法
Aug 21 Python
python GUI库图形界面开发之PyQt5多线程中信号与槽的详细使用方法与实例
Mar 08 Python
浅谈pymysql查询语句中带有in时传递参数的问题
Jun 05 Python
Python实现列表索引批量删除的5种方法
Nov 16 Python
Pycharm安装python库的方法
Nov 24 Python
python数字图像处理实现图像的形变与缩放
Jun 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
PHP网页游戏学习之Xnova(ogame)源码解读(十三)
2014/06/26 PHP
在Windows XP下安装Apache+MySQL+PHP环境
2015/02/22 PHP
php中mysql连接方式PDO使用详解
2015/02/25 PHP
整理php防注入和XSS攻击通用过滤
2015/09/13 PHP
使用PHP下载CSS文件中的所有图片【几行代码即可实现】
2016/12/14 PHP
浅谈PHP5.6 与 PHP7.0 区别
2019/10/09 PHP
Nigma vs Alliance BO5 第一场2.14
2021/03/10 DOTA
Javascript中找到子元素在父元素内相对位置的代码
2012/07/21 Javascript
js实现进度条的方法
2015/02/13 Javascript
jQuery如何防止这种冒泡事件发生
2015/02/27 Javascript
jQuery简单实现QQ空间点赞已经取消点赞
2015/04/02 Javascript
javascript实现十秒钟后注册按钮可点击的方法
2015/05/13 Javascript
jQuery EasyUI之DataGrid使用实例详解
2016/01/04 Javascript
JS中的数组方法笔记整理
2016/07/26 Javascript
AngularJS实现按钮提示与点击变色效果
2016/09/07 Javascript
jQuery自定义图片上传插件实例代码
2017/04/04 jQuery
es6学习之解构时应该注意的点
2017/08/29 Javascript
node 利用进程通信实现Cluster共享内存
2017/10/27 Javascript
js中如何完美的解析数据
2018/03/18 Javascript
JS点击动态添加标签、删除指定标签的代码
2018/04/18 Javascript
vue-cli webpack配置文件分析
2019/05/20 Javascript
Vue.js如何使用Socket.IO的示例代码
2019/09/05 Javascript
Python模拟三级菜单效果
2017/09/11 Python
python最小生成树kruskal与prim算法详解
2019/01/17 Python
Django如何开发简单的查询接口详解
2019/05/17 Python
python SVM 线性分类模型的实现
2019/07/19 Python
Python将string转换到float的实例方法
2019/07/29 Python
pyCharm 设置调试输出窗口中文显示方式(字符码转换)
2020/06/09 Python
浅谈盘点5种基于Python生成的个性化语音方法
2021/02/05 Python
Shein英国:女性时尚网上商店
2019/04/10 全球购物
《九色鹿》教学反思
2014/02/27 职场文书
毕业设计指导教师评语
2014/12/30 职场文书
2015年前台个人工作总结
2015/04/03 职场文书
小学生安全保证书
2015/05/09 职场文书
2015年社区党建工作汇报材料
2015/06/25 职场文书
用python画城市轮播地图
2021/05/28 Python