详解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中的字符串知识点
Apr 14 Python
在Python中封装GObject模块进行图形化程序编程的教程
Apr 14 Python
Python实现PS图像明亮度调整效果示例
Jan 23 Python
使用python搭建服务器并实现Android端与之通信的方法
Jun 28 Python
详解python调用cmd命令三种方法
Jul 08 Python
Python实现计算对象的内存大小示例
Jul 10 Python
Python3 requests文件下载 期间显示文件信息和下载进度代码实例
Aug 16 Python
python 列表、字典和集合的添加和删除操作
Dec 16 Python
文件上传服务器-jupyter 中python解压及压缩方式
Apr 22 Python
2021年值得向Python开发者推荐的VS Code扩展插件
Jan 25 Python
如何在Python中创建二叉树
Mar 30 Python
微信小程序调用python模型
Apr 21 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数组相关函数汇总
2015/03/24 PHP
php使用Jpgraph绘制饼状图的方法
2015/06/10 PHP
利用PHP生成静态html页面的原理
2016/09/30 PHP
在Mac OS下搭建LNMP开发环境的步骤详解
2017/03/10 PHP
javascript各浏览器中option元素的表现差异
2011/04/07 Javascript
JavaScript高级程序设计 DOM学习笔记
2011/09/10 Javascript
JS 跳转页面延迟2种方法
2013/03/29 Javascript
js中split和replace的用法实例
2015/02/28 Javascript
jquery实现图片水平滚动效果代码分享
2015/08/26 Javascript
jQuery页面元素动态添加后绑定事件丢失方法,非 live
2016/06/16 Javascript
微信小程序动态添加分享数据
2017/06/14 Javascript
打字效果动画的4种实现方法(超简单)
2017/10/18 Javascript
vue-cli 脚手架基于Nightwatch的端到端测试环境的过程
2018/09/30 Javascript
Vue.js@2.6.10更新内置错误处机制Fundebug同步支持相应错误监控
2019/05/13 Javascript
JS设置自定义快捷键并实现图片上下左右移动
2019/10/17 Javascript
vue微信分享插件使用方法详解
2020/02/18 Javascript
Python找出文件中使用率最高的汉字实例详解
2015/06/03 Python
python+POP3实现批量下载邮件附件
2018/06/19 Python
python保存二维数组到txt文件中的方法
2018/11/15 Python
python3 实现验证码图片切割的方法
2018/12/07 Python
详解PyTorch中Tensor的高阶操作
2019/08/18 Python
Python : turtle色彩控制实例详解
2020/01/19 Python
tensorflow使用指定gpu的方法
2020/02/04 Python
Python 内存管理机制全面分析
2021/01/16 Python
Python3+Django get/post请求实现教程详解
2021/02/16 Python
canvas学习总结三之绘制路径-线段
2019/01/31 HTML / CSS
欧洲领先的技术商店:eibmarkt.com
2019/05/10 全球购物
小学班长竞选演讲稿
2014/04/24 职场文书
关于安全的广播稿
2014/10/23 职场文书
作文评语集锦
2014/12/25 职场文书
老公保证书怎么写
2015/02/26 职场文书
幼师辞职信范文
2015/02/27 职场文书
中小企业员工手册范本
2015/05/14 职场文书
党员发展大会主持词
2015/07/03 职场文书
领导欢送会主持词
2015/07/06 职场文书