魔术方法 / 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. paramiko类Fabric主机管理

    环境:Linux python3.5 要求:类 Fabric 主机管理程序开发:1. 运行程序列出主机组或者主机列表2. 选择指定主机或主机组3. 选择让主机或者主机组执行命令或者向其传输文件(上传/ ...

  2. 01--是时候让我们谈谈一致性hash了

    --------------------- 假如你有图中三个盒子,我们有代号为 1,4,5,12 这四样东西 那根据代号作为主键,将东西放到盒子了,该如何放置? 我们可以对代号取模 1 mod 3 = ...

  3. NOIP2018 集训(二)

    A题 神炎皇 问题描述 神炎皇乌利亚很喜欢数对,他想找到神奇的数对. 对于一个整数对 \((a,b)\) ,若满足 \(a+b\leq n\) 且 \(a+b\) 是 \(ab\) 的因子,则称 为神 ...

  4. 孤荷凌寒自学python第三十三天python的文件操作初识

     孤荷凌寒自学python第三十三天python的文件操作初识 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天开始自学python的普通 文件操作部分的内容. 一.python的文件打开 ...

  5. centos6 install cobbler

    cobbler 安装   一:定义yum源 wget -c -O CentOS-Base.repo http://mirrors.163.com/.help/CentOS6-Base-163.repo ...

  6. [g2o]C++图优化库

    g2o以图模型表达上述最小二乘问题:比较适合解决SLAM问题 http://openslam.org http://wiki.ros.org/g2o

  7. Linux查看端口被占用情形

    查看某端口的占用情况: lsof -i:<端口号> 例如:lsof -i:8080 netstat -apn|grep <端口号> 例如: netstat -apn | gre ...

  8. ssh 免交互登录 ,远程执行命令脚本。

    ##免交互SSH登录auto_login_ssh () {    expect -c "set timeout -1;                spawn -noecho ssh -o ...

  9. Spring 学习笔记(四)—— XML配置依赖注入

    依赖注入(DI)与控制反转(IoC)是同一个概念,都是为了处理对象间的依赖关系. 通过DI/IoC容器,相互依赖的对象由容器负责创建和装配,而不是在代码中完成. Spring支持通过setter方法和 ...

  10. KindleEditor insertfile初始化多个

    KindEditor.ready(function (K) { var editor = K.editor({ allowFileManager: true }); K('#insertfile'). ...