详解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 xml.etree.ElementTree遍历xml所有节点实例详解
Dec 04 Python
python 矩阵增加一行或一列的实例
Apr 04 Python
基于DataFrame筛选数据与loc的用法详解
May 18 Python
Python实现去除列表中重复元素的方法总结【7种方法】
Feb 16 Python
Python安装Flask环境及简单应用示例
May 03 Python
pandas实现to_sql将DataFrame保存到数据库中
Jul 03 Python
postman传递当前时间戳实例详解
Sep 14 Python
Python如何在循环内使用list.remove()
Jun 01 Python
python自定义函数def的应用详解
Jun 03 Python
Python下载网易云歌单歌曲的示例代码
Aug 12 Python
python 多线程共享全局变量的优劣
Sep 24 Python
python 如何停止一个死循环的线程
Nov 24 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和ACCESS写聊天室(十)
2006/10/09 PHP
PHP+JS无限级可伸缩菜单详解(简单易懂)
2007/01/02 PHP
下拉列表多级联动dropDownList示例代码
2013/06/27 PHP
实用的简单PHP分页集合包括使用方法
2013/10/21 PHP
完整删除ecshop中获取店铺信息的API
2014/12/24 PHP
Netbeans 8.2与PHP相关的新特性介绍
2016/10/08 PHP
javascript实现动态CSS换肤技术的脚本
2007/06/29 Javascript
js 目录列举函数
2008/11/06 Javascript
js URL参数的拼接方法比较
2012/02/15 Javascript
JavaScript实现查找字符串中第一个不重复的字符
2014/12/29 Javascript
Jquery实现的简单轮播效果【附实例】
2016/04/19 Javascript
nodejs实现发出蜂鸣声音(系统报警声)的方法
2017/01/18 NodeJs
Angular4自制一个市县二级联动组件示例
2017/11/21 Javascript
vue.js实现的绑定class操作示例
2018/07/06 Javascript
js实现验证码干扰(动态)
2021/02/23 Javascript
[51:05]DOTA2上海特级锦标赛主赛事日 - 5 败者组决赛Liquid VS EG第一局
2016/03/06 DOTA
Python的Django REST框架中的序列化及请求和返回
2016/04/11 Python
使用Python编写一个最基础的代码解释器的要点解析
2016/07/12 Python
Python实现判断一个字符串是否包含子串的方法总结
2017/11/21 Python
python地震数据可视化详解
2019/06/18 Python
详解PyTorch中Tensor的高阶操作
2019/08/18 Python
Python检测端口IP字符串是否合法
2020/06/05 Python
Django REST Swagger实现指定api参数
2020/07/07 Python
安装并免费使用Pycharm专业版(学生/教师)
2020/09/24 Python
Python Spyder 调出缩进对齐线的操作
2021/02/26 Python
制药工程专业个人求职自荐信
2014/01/25 职场文书
四年级科学教学反思
2014/02/10 职场文书
学习交流会主持词
2014/04/01 职场文书
小班下学期评语
2014/05/04 职场文书
捐书活动总结
2014/05/04 职场文书
安全横幅标语
2014/06/09 职场文书
校园新闻稿范文
2015/07/18 职场文书
八年级英语教学反思
2016/02/15 职场文书
Python 实现定积分与二重定积分的操作
2021/05/26 Python
JavaScript中的宏任务和微任务详情
2021/11/27 Javascript
浅谈Redis的事件驱动模型
2022/05/30 Redis