Python 的 Magic Methods 指南(8)

你也许已经知道,在Python中,方法是最高级的对象。这意味着他们也可以被传递到方法中,就像其他对象一样。这是一个非常惊人的特性。

在Python中,一个特殊的魔法方法可以让类的实例的行为表现的像函数一样,你可以调用它们,将一个函数当做一个参数传到另外一个函数中等等。这是一个非常强大的特性,其让Python编程更加舒适甜美。

__call__(self, [args...])

允许一个类的实例像函数一样被调用。实质上说,这意味着 x() x.__call__() 是相同的。注意 __call__ 的参数可变。这意味着你可以定义 __call__ 为其他你想要的函数,无论有多少个参数。

__call__ 在那些类的实例经常改变状态的时候会非常有效。“调用”这个实例是一种改变这个对象状态的直接和优雅的做法。比如这样一个例子,一个类表示了一个实体在飞机上的位置:

class Entity: '''表示一个实体的类。调用该类以更新实体的位置。''' def __init__(self, size, x, y): self.x, self.y = x, y self.size = size def __call__(self, x, y): '''Change the position of the entity.''' self.x, self.y = x, y # snip... 会话管理器

在Python 2.5中,为了代码重用而新定义了一个关键字with,其也就带来了一种with语句。会话管理在Python中并不罕见(之前是作为库的一部分而实现的),不过直到PEP 343被接受后,其就作为了一种一级语言结构。你也许在之前看到过这样的语句:

with open('foo.txt') as bar: # 执行一些针对bar的操作

会话管理器通过包装一个with语句来设置和清理相应对象的行为。会话管理器的行为通过两个魔方方法来决定:

__enter__(self)

定义了当使用with语句的时候,会话管理器在块被初始创建事要产生的行为。请注意,__enter__的返回值与with语句的目标或者as后的名字绑定。

__exit__(self, exception_type, exception_value, traceback)

定义了当一个代码块被执行或者终止后,会话管理器应该做什么。它可以被用来处理异常、执行清理工作或做一些代码块执行完毕之后的日常工作。如果代码块执行成功,exception_type,exception_value,和traceback将会为None。否则,你可以选择处理这个异常或者是直接交给用户处理。如果你想处理这个异常的话,请确保__exit__在所有语句结束之后返回True。如果你想让异常被会话管理器处理的话,那么就让其产生该异常。

__enter__和__exit__对于那些定义良好以及有普通的启动和清理行为的类是很有意义的。你也可以使用这些方法来创建一般的可以包装其它对象的会话管理器。下面是一个例子:

class Closer: '''通过with语句和一个close方法来关闭一个对象的会话管理器。''' def __init__(self, obj): self.obj = obj def __enter__(self): return self.obj # bound to target def __exit__(self, exception_type, exception_val, trace): try: self.obj.close() except AttributeError: # obj isn't closable print 'Not closable.' return True # exception handled successfully

下面是一个实际使用Closer的例子,使用一个FTP连接来证明(一个可关闭的套接字):

>>> from magicmethods import Closer
>>> from ftplib import FTP
>>> with Closer(FTP('ftp.somesite.com')) as conn:
...    conn.dir()
...
>>> conn.dir()
>>> with Closer(int(5)) as i:
...    i += 1
...
Not closable.
>>> i
6

看到我们的包装器如何友好地处理恰当和不不恰当的行为了吗?这是会话管理器和魔法方法的强大功能。请注意,Python标准库包括了一个叫作 contextlib 的模块,其包含了一个会话管理器,contextlib.closing()完成了类似的功能(当一个对象没有close()方法时则没有任何处理)。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/cb1b2f78dd9df2088d69413cabe7ac94.html