Python的程序结构[1] -> 方法/Method[2] -> 魔术方法 __init__ / __del__ / __new__
魔术方法 / 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__的更多相关文章
- Python的程序结构[1] -> 方法/Method[3] -> 魔术方法 __getattr__ 与代理模式
__getattr__ 方法 __getattr__ 方法当对象调用内部属性(包括方法等)且未找到对应属性的时候会调用的特殊方法.利用这一特性,可是对函数实现一个代理模式. __getattr__方法 ...
- Python的程序结构[1] -> 方法/Method[4] -> 魔术方法 __call__ / __str__ / __repr__
__call__ 方法 __call__ 是当对象被调用时会调用的方法,允许一个对象(类的实例等)像函数一样被调用,也可以传入参数. 1 class Foo(): 2 def __init__(sel ...
- Python的程序结构[1] -> 方法/Method[0] -> 类实例方法、私有方法和抽象方法
类实例方法.私有方法和抽象方法 Python中最常用的就是类实例方法,类似于属性中的类实例属性,同时,也存在与私有属性类似方法,即私有方法,下面介绍这两种常见的方法,以及一种特殊意义的类实例方法 -- ...
- C++/Php/Python/Shell 程序按行读取文件或者控制台方法总结。
C++/Php/Python/Shell 程序按行读取文件或者控制台方法总结. 一.总结 C++/Php/Python/Shell 程序按行读取文件或者控制台(php读取标准输入:$fp = fope ...
- Python的程序结构[1] -> 方法/Method[1] -> 静态方法、类方法和属性方法
静态方法.类方法和属性方法 在 Python 中有三种常用的方法装饰器,可以使普通的类实例方法变成带有特殊功能的方法,分别是静态方法.类方法和属性方法. 静态方法 / Static Method 在 ...
- Python的程序结构[4] -> 函数/Function[0] -> 函数与方法的区别
函数与方法的区别 / Distinction of Function and Method 关于函数与方法的区别,可根据两者的定义看出, 函数function -- A series of state ...
- Python的程序结构[7] -> 生成器/Generator -> 生成器浅析
生成器 / Generator 目录 关于生成器 生成器与迭代器 生成器的建立 通过迭代生成器获取值 生成器的 close 方法 生成器的 send 方法 生成器的 throw 方法 空生成器的检测方 ...
- Python的程序结构[2] -> 类/Class[1] -> 基类与继承
基类与继承 / Base Class and Inheritance Class 面向对象的特性使得 Python 中不可避免地需要使用到类和类的继承,类的继承可以使得代码很好的被重用.下面以一些代码 ...
- 零基础小白Python入门必看:面向对象之典型魔术方法
随机推荐
- LeetCode - Merge Interval.
Merge Intervals 2014.2.26 21:28 Given a collection of intervals, merge all overlapping intervals. Fo ...
- 《Cracking the Coding Interview》——第5章:位操作——题目3
2014-03-19 05:57 题目:给定一个整数N,求出比N大,而且二进制表示中和N有相同个数的‘1’的最小的数,比如3是‘11’,接下来的5是‘101’,再接下来的6是‘110’. 解法:从低位 ...
- 1099 Build A Binary Search Tree (30 分)(查找二叉树)
还是中序遍历建树 #include<bits/stdc++.h> using namespace std; ; struct node { int data; int L,R; }s[N] ...
- hnust 分蛋糕
问题 B: 分蛋糕 时间限制: 1 Sec 内存限制: 128 MB提交: 2430 解决: 966[提交][状态][讨论版] 题目描述 今天是DK生日,由于DK的朋友很多,所以DK在蛋糕店定制了 ...
- Leetcode 665.非递减数列
非递减数列 给定一个长度为 n 的整数数组,你的任务是判断在最多改变 1 个元素的情况下,该数组能否变成一个非递减数列. 我们是这样定义一个非递减数列的: 对于数组中所有的 i (1 <= i ...
- springboot13 Hikari 和Introspector
SpringBoot Initializr Introspector(内省) class TestReflect { @Test fun testReflect() { //获取字节码对象 val c ...
- Python 的音乐库
前言 其实处理这个用 Matlab 最方便,之前把 guitar-synthesizer 从 Matlab 移植到 Python,过程中更是体会到了这一点. 不过 Matlab 安装包又大,启动又慢, ...
- sharePreference的几个重点
一. SharePreferences是用来存储一些简单配置信息的一种机制,使用Map数据结构来存储数据,以键值对的方式存储,采用了XML格式将数据存储到设备中,文件存放在/data/data/&l ...
- 转载:Android SQLite数据库版本升级原理解析
Android使用SQLite数据库保存数据,那数据库版本升级是怎么回事呢,这里说一下. 一.软件v1.0 安装v1.0,假设v1.0版本只有一个account表,这时走继承SQLiteOpenHel ...
- ci重写 配置文件
server { listen 80; #listen [::]:80; server_name wangyongshun.xyz www.wangyongshun.xyz; index index. ...