构造方法
我们最为熟知的基本的魔法方法就是 __init__
,我们可以用它来指明一个对象初始化的行为。然而,当我们调用
x = SomeClass()
的时候, __init__
并不是第一个被调用的方法。事实上,第一个被调用的是 __new__
,这个
方法才真正地创建了实例。当这个对象的生命周期结束的时候, __del__
会被调用。让我们近一步理解这三个方法:
-
__new__(cls,[...)
__new__
是对象实例化时第一个调用的方法,它只取下cls
参数,并把其他参数传给__init__
。__new__
很少使用,但是也有它适合的场景,尤其是当类继承自一个像元组或者字符串这样不经常改变的类型的时候。我不打算深入讨论
__new__
,因为它并不是很有用,Python文档 <http://www.python.org/download/releases/2.2/descrintro/#__new__>
_ 中
有详细的说明。 -
__init__(self,[...])
类的初始化方法。它获取任何传给构造器的参数(比如我们调用
x = SomeClass(10, 'foo')
,__init__
就会接到参数
10
和'foo'
。__init__
在Python的类定义中用的最多。 -
__del__(self)
__new__
和__init__
是对象的构造器,__del__
是对象的销毁器。它并非实现了语句del x
(因此该语句不等同于x.__del__()
)。而是定义了当对象被垃圾回收时的行为。
当对象需要在销毁时做一些处理的时候这个方法很有用,比如socket
对象、文件对象。但是需要注意的是,当Python解释器退出但对象仍然存活的时候,__del__
并不会
执行。 所以养成一个手工清理的好习惯是很重要的,比如及时关闭连接。
这里有个 __init__
和 __del__
的例子::
from os.path import join
class FileObject:
'''文件对象的装饰类,用来保证文件被删除时能够正确关闭。'''
def __init__(self, filepath='~', filename='sample.txt'):
# 使用读写模式打开filepath中的filename文件
self.file = open(join(filepath, filename), 'r+')
def __del__(self):
self.file.close()
del self.file
类的表示
__str__(self)
定义对类的实例调用 str()
时的行为。
__repr__(self)
定义对类的实例调用 repr()
时的行为。 str()
和 repr()
最主要的差别在于“目标用户”。 repr()
的作用是产生机器可读的输出(大部分情况下,其输出可以作为有效的Python代码),而 str()
则产生人类可读的输出。
__dir__(self)
定义对类的实例调用 dir()
时的行为,这个方法应该向调用者返回一个属性列表。一般来说,没必要自己实现 __dir__
。但是如果你重定义了 __getattr__
或者 __getattribute__
(下个部分会介绍),乃至使用动态生成的属性,以实现类的交互式使用,那么这个魔法方法是必不可少的。
反射
你可以通过定义魔法方法来控制用于反射的内建函数 isinstance
和 issubclass
的行为。下面是对应的魔法方法:
-
__instancecheck__(self, instance)
检查一个实例是否是你定义的类的一个实例(例如
isinstance(instance, class)
)。 -
__subclasscheck__(self, subclass)
检查一个类是否是你定义的类的子类(例如
issubclass(subclass, class)
)
上下文管理
当对象使用 with
声明创建时,上下文管理器允许类做一些设置和清理工作。上下文管理器的行为由下面两个魔法方法所定义:
-
__enter__(self)
定义使用
with
声明创建的语句块最开始上下文管理器应该做些什么。注意__enter__
的返回值会赋给with
声明的目标,也就是as
之后的东西。 -
__exit__(self, exception_type, exception_value, traceback)
定义当
with
声明语句块执行完毕(或终止)时上下文管理器的行为。它可以用来处理异常,进行清理,或者做其他应该在语句块结束之后立刻执行的工作。如果语句块顺利执行,exception_type
,exception_value
和traceback
会是None
。否则,你可以选择处理这个异常或者让用户来处理。