详解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 (2)
Oct 31 Python
Python的加密模块md5、sha、crypt使用实例
Sep 28 Python
Python简单删除目录下文件以及文件夹的方法
May 27 Python
python线程池threadpool实现篇
Apr 27 Python
基于Python log 的正确打开方式
Apr 28 Python
Python装饰器用法实例总结
May 26 Python
使用pandas实现csv/excel sheet互相转换的方法
Dec 10 Python
简单了解python协程的相关知识
Aug 31 Python
Python实现多线程/多进程的TCP服务器
Sep 03 Python
python根据文本生成词云图代码实例
Nov 15 Python
pycharm激活码有效到2020年11月底
Sep 18 Python
Django项目配置Memcached和Redis, 缓存选择哪个更有优势
Apr 06 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
Zend Framework页面缓存实例
2014/06/25 PHP
微信支付扫码支付php版
2016/07/22 PHP
从新浪弄下来的全屏广告代码 与使用说明
2007/03/15 Javascript
JavaScript学习笔记(二) js对象
2011/10/25 Javascript
javascript使用location.search的示例
2013/11/05 Javascript
jquery xMarquee实现文字水平无缝滚动效果
2014/04/29 Javascript
js数值计算时使用parseInt进行数据类型转换(jquery)
2014/10/07 Javascript
让javascript加载速度倍增的方法(解决JS加载速度慢的问题)
2014/12/12 Javascript
jQuery+AJAX实现无刷新下拉加载更多
2015/07/03 Javascript
JavaScript的jQuery库插件的简要开发指南
2015/08/12 Javascript
VueJs与ReactJS和AngularJS的异同点
2016/12/12 Javascript
Node.js的特点详解
2017/02/03 Javascript
jQuery实现大图轮播
2017/02/13 Javascript
js实现简单的选项卡效果
2017/02/23 Javascript
AngularJS路由Ui-router模块用法示例
2017/05/29 Javascript
EasyUI Tree树组件无限循环的解决方法
2017/09/27 Javascript
JavaScript禁用右键单击优缺点分析
2019/01/20 Javascript
手把手教你 CKEDITOR 4 实现Dialog 内嵌 IFrame操作详解
2019/06/18 Javascript
js实现简单页面全屏
2019/09/17 Javascript
解决父组件将子组件作为弹窗调用只执行一次created的问题
2020/07/24 Javascript
理解JavaScript中的对象
2020/08/25 Javascript
vue.js封装switch开关组件的操作
2020/10/26 Javascript
[40:19]完美世界DOTA2联赛PWL S3 Rebirth vs CPG 第二场 12.18
2020/12/19 DOTA
Python中的闭包总结
2014/09/18 Python
python的继承知识点总结
2018/12/10 Python
Python调用接口合并Excel表代码实例
2020/03/31 Python
python实现处理mysql结果输出方式
2020/04/09 Python
迪拜航空官方网站:flydubai
2017/04/20 全球购物
Dr. Martens马汀博士法国官网:马丁靴鼻祖
2020/01/15 全球购物
大学自我鉴定范文
2013/12/26 职场文书
英文留学推荐信范文
2014/01/25 职场文书
银行简历自我评价
2014/02/11 职场文书
典型事迹材料范文
2014/12/29 职场文书
房屋租赁意向书范本
2015/05/09 职场文书
2016年4月份红领巾广播稿
2015/12/21 职场文书
Python数据类型最全知识总结
2021/05/31 Python