魔术方法 / Magic Method


魔法方法就是可以给你的类增加魔力的特殊方法(实质应称为特殊方法,魔术方法在JavaScript中有所体现,对象具有不透明特性,而且无法在自定义对象中模拟这些行为),如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一切都是自动发生的。它们经常是两个双下划线包围来命名的(比如 __init__,__lt__),Python的魔法方法是非常强大的。下面介绍几种常用的魔术方法

__init__ 方法


__init__ 构造器/构造方法,当一个实例被创建的时候初始化的方法。但是它并不是实例化调用的第一个方法,__new__才是实例化对象调用的第一个方法

 class Foo:
def __init__(self, param):
print('Init method get parameter: %s' % param)
f = Foo('PARAM')

上面代码中的 Foo 类定义了一个 __init__ 构造方法,这个方法接收一个参数,但在使用时,这个方法可以不被显式的调用(类继承的时候有时会进行父类构造方法的显式调用),而是通过第 4 行的实例化方式来进行调用,运行上面的代码可以得到结果如下,

Init method get parameter: PARAM

从结果可以看出,在一个类进行实例化生成实例的时候,__init__ 构造方法会被自动调用。

__del__ 方法


__del__ 析构器/析构方法,与 __init__ 相反,当实例被销毁的时候调用的方法,也是 del() 函数会调用的方法。

 class Foo():
def __init__(self):
print('__init__ method called') def __del__(self):
print('__del__ method called') f = Foo()
del(f)

上面的代码定义了一个带有构造方法可析构方法的 Foo 类,运行代码可以得到如下结果,

__init__ method called
__del__ method called

从结果可以看出,构造和析构两个方法都被调用了,构造方法在第 8 行被调用,而析构方法则是在第 9 行被 del 函数所调用。

__new__ 方法


__new__ 方法是实例化调用的第一个方法,在 __init__ 方法之前调用,它只取下 cls参数,并把其他参数传给 __init__。__new__ 很少使用,但是也有它适合的场景,尤其是当类继承自一个像元组或者字符串这样不经常改变的类型的时候。

__new__ 方法使用时注意以下几点:

1. __new__ 是在一个对象实例化的时候所调用的第一个方法;

2. 它的第一个参数这个类其他的参数是用来直接传递给 __init__ 方法;

3. __new__ 决定是否要使用自身的 __init__ 方法,因为 __new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则 __init__ 不会被调用,只有 __new__ 返回了实例对象,__init__ 才会被调用执行;

4. __new__ 主要是用于继承一个不可变的类型比如一个 tuple 或者 string;

5. __new__ return的是一个构建的实例

__new__ 实现单例模式

 class Person:
def __init__(self, name, age):
self.name = name
self.age = age def __new__(cls, *args, **kwargs):
print(id(cls), id(Person)) # Id is same
# If instance of class has exist, return the instance without generate a new one
if not hasattr(cls, 'instance'):
cls.instance = super(Person, cls).__new__(cls) # Generate a instance
return cls.instance a = Person('p1', 20)
print(a.name, a.age) # 'p1', 20
b = Person('p2', 21)
print(a.name, a.age) # 'p2', 21
print(b.name, b.age) # 'p2', 21
print(a is b) # True

上面的代码利用 __new__ 方法实现了一种单例模式,

首先是定义了一个类以及构造方法,然后定义了这个类的 __new__ 方法,注意这里的 __new__ 方法接收的第一个参数为cls,也就是当前的类,可以通过第 7 行输出两者的 id 进行比较,最终可以发现两者 id 相同。

在第 8-10 行中,利用一个判断语句判断当前类中是否含有 instance 属性,若有则直接返回,若没有则利用 super 通过 MRO 查找到 Person 的 MRO 搜索顺序中的下一个类(本例中是 object)来调用其 __new__ 方法,并传入当前 cls 作为参数。这样便实现了一个简单的单例模式。

然后是第 11 行,返回一个实例,这个返回的实例将会作为 __init__ 方法的第一个参数传给 self。

最后对单例模式进行验证,在 12-13 行中生成一个实例 a,并查看内部属性,发现其结果与传入值相同,在 15-17 行再生成一个实例 b,同时对 a 和 b 进行查看发现, a 的属性由于 b 的实例化也被改变了,最后通过 18 行查看发现,a 和 b 是同一个实例。

也就是说,无论 Person 实例化多少次,都只会产生一个实例对象传给 __init__ 方法,只不过每次的初始化函数参数不同,从而改变了实例的属性值。

相关阅读


1. super

2. MRO 搜索顺序

参考链接


http://www.cnblogs.com/styier/p/6111370.html

Python的程序结构[1] -> 方法/Method[2] -> 魔术方法 __init__ / __del__ / __new__的更多相关文章

  1. Python的程序结构[1] -> 方法/Method[3] -> 魔术方法 __getattr__ 与代理模式

    __getattr__ 方法 __getattr__ 方法当对象调用内部属性(包括方法等)且未找到对应属性的时候会调用的特殊方法.利用这一特性,可是对函数实现一个代理模式. __getattr__方法 ...

  2. Python的程序结构[1] -> 方法/Method[4] -> 魔术方法 __call__ / __str__ / __repr__

    __call__ 方法 __call__ 是当对象被调用时会调用的方法,允许一个对象(类的实例等)像函数一样被调用,也可以传入参数. 1 class Foo(): 2 def __init__(sel ...

  3. Python的程序结构[1] -> 方法/Method[0] -> 类实例方法、私有方法和抽象方法

    类实例方法.私有方法和抽象方法 Python中最常用的就是类实例方法,类似于属性中的类实例属性,同时,也存在与私有属性类似方法,即私有方法,下面介绍这两种常见的方法,以及一种特殊意义的类实例方法 -- ...

  4. C++/Php/Python/Shell 程序按行读取文件或者控制台方法总结。

    C++/Php/Python/Shell 程序按行读取文件或者控制台方法总结. 一.总结 C++/Php/Python/Shell 程序按行读取文件或者控制台(php读取标准输入:$fp = fope ...

  5. Python的程序结构[1] -> 方法/Method[1] -> 静态方法、类方法和属性方法

    静态方法.类方法和属性方法 在 Python 中有三种常用的方法装饰器,可以使普通的类实例方法变成带有特殊功能的方法,分别是静态方法.类方法和属性方法. 静态方法 / Static Method 在 ...

  6. Python的程序结构[4] -> 函数/Function[0] -> 函数与方法的区别

    函数与方法的区别 / Distinction of Function and Method 关于函数与方法的区别,可根据两者的定义看出, 函数function -- A series of state ...

  7. Python的程序结构[7] -> 生成器/Generator -> 生成器浅析

    生成器 / Generator 目录 关于生成器 生成器与迭代器 生成器的建立 通过迭代生成器获取值 生成器的 close 方法 生成器的 send 方法 生成器的 throw 方法 空生成器的检测方 ...

  8. Python的程序结构[2] -> 类/Class[1] -> 基类与继承

    基类与继承 / Base Class and Inheritance Class 面向对象的特性使得 Python 中不可避免地需要使用到类和类的继承,类的继承可以使得代码很好的被重用.下面以一些代码 ...

  9. 零基础小白Python入门必看:面向对象之典型魔术方法

随机推荐

  1. 《数据结构与算法分析:C语言描述》复习——第五章“堆”——二叉堆

    2014.06.15 22:14 简介: 堆是一种非常实用的数据结构,其中以二叉堆最为常用.二叉堆可以看作一棵完全二叉树,每个节点的键值都大于(小于)其子节点,但左右孩子之间不需要有序.我们关心的通常 ...

  2. 剑指Offer - 九度1348 - 数组中的逆序对

    剑指Offer - 九度1348 - 数组中的逆序对2014-01-30 23:19 题目描述: 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个 ...

  3. Linux忘记root密码的解决办法

    这里以centos6为例: 第一步:先将系统重新启动,在读秒的时候按下任意键就会出现如下图的菜单界面: 第二步:按下『e』就能够进入grub的编辑模式,如图: 第三步:将光标移动到kernel那一行, ...

  4. 移动APP自动化测试框架对比

    转自微信公众号:腾讯移动品质中心TMQ 移动APP的UI自动化测试长久以来一直是一个难点,难点在于UI的”变”, 变化导致自动化用例的大量维护.从分层测试的角度,自动化测试应该逐层进行.最大量实现自动 ...

  5. JMeter学习笔记(六) 文件下载接口测试

    本次测试的是文件下载接口,文件是PDF文档,步骤如下: 1.通过jmeter的录制功能,获取了文件下载接口的地址和参数,和其他的HTTP请求一样的配置 2.执行此接口后,察看结果树,点击下载接口的结果 ...

  6. Singleton patterns 单件(创建型模式)

    1.模式分类 1.1  从目的来看: •      – 创建型(Creational)模式:负责对象创建. •      – 结构型(Structural)模式:处理类与对象间的组合. •      ...

  7. Python全栈 MySQL 数据库 (SQL查询、备份、恢复、授权)

    ParisGabriel              每天坚持手写  一天一篇  决定坚持几年 为了梦想为了信仰    开局一张图   今天接着昨天的说   索引有4种:      普通 索引 :ind ...

  8. Linux常用命令及工具记录(持续更新)

    一.命令 convmv   作用:文件名的编码转换   安装:sudo apt-get install convmv   使用:convmv * -f gbk -t utf8 --notest   c ...

  9. javascript replace 替换全部字符

    $("#pageNote").html($("#note3").val().replace(/ /g, "").replace(/<b ...

  10. hdu 1195 Open the Lock (BFS)

    Open the Lock Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...