Python 高手编程系列九百一十:代理

代理提供对昂贵或远程资源的间接访问。代理(Proxy)在客户端(Client)和主题
(Subject)之间
它旨在优化主题的访问,如果它们是昂贵的。例如,第 12 章中描述的 memoize()和
lru_cache()装饰器可以被视为代理。
代理还可以用于提供对主题的智能访问。例如,可以将大视频文件包装到代理中,当
用户只是请求其标题时,这可以避免将它们加载到内存中。
urllib.request 模块中有这样一个例子。urlopen 是位于远程 URL 的内容的代理。
创建时,可以独立于内容本身检索头信息,而无需读取响应的其余部分,如下所示:

class Url(object):
… def init(self, location):
… self._url = urlopen(location)
… def headers(self):
… return dict(self.url.headers.items())
… def get(self):
… return self.url.read()

python_org = Url(‘http://python.org’)
python_org.headers().keys()
dict_keys([‘Accept-Ranges’, ‘Via’, ‘Age’, ‘Public-Key-Pins’, ‘X-Clacks-
Overhead’, ‘X-Cache-Hits’, ‘X-Cache’, ‘Content-Type’, ‘Content-Length’,
‘Vary’, ‘X-Served-By’, ‘Strict-Transport-Security’, ‘Server’, ‘Date’,
‘Connection’, ‘X-Frame-Options’])
通过查看头信息中的 last-modified 来确定页面是否在更新本地副本之前发生更
改。让我们举一个大文件的例子如下:
ubuntu_iso = Url(‘http://ubuntu.mirrors.proxad.net/hardy/ubuntu-8.04-
desktop-i386.iso’)
ubuntu_iso.headers()[‘Last-Modified’]
‘Wed, 23 Apr 2008 01:03:34 GMT’
代理的另一个使用范例是数据唯一性。
例如,让我们考虑一个网站,在多个位置呈现相同的文档。文档会附加上每个位置的
特定字段,例如页面访问数和几个权限设置。可以使用代理来处理特定位置相关的情况,
并且是指向原始文档而不是复制它。因此,给定文档可以具有许多代理,并且如果其内容
改变,则所有位置都将受益,因为它们不必处理版本同步。
一般来说,代理模式主要用于实现可能存在于其他地方的某物的本地句柄。
• 使处理更快。
• 避免外部资源访问。
• 减少内存负载。
• 确保数据唯一性。
外观
外观(facade)提供对子系统的高层次,简单地访问。
外观只不过是使用应用程序功能的快捷方式,而不必处理子系统的底层复杂性。可以
这样做,例如,可以通过在包级别上提供高级功能来完成。
外观通常在现有系统上使用,其中包的频繁使用是在高级功能中合成的。通常,不需
要类来提供这样的模式,在__init
.py 模块中的简单函数就足够了。
requests 包(参考 http://docs.python-requests.org/)是一个很好的示例项目,它在复
杂并且综合的接口上提供了一个大的外观。它通过为开发人员提供易于阅读的简洁的 API,
真正简化了在 Python 中处理 HTTP 请求和响应的棘手问题。它甚至打出这样的广告易用的
HTTP 库(HTTP for humans)。这种易于使用总是要付出代价的,但最终的权衡和额外的开
销不会吓跑大多数人,他们依然将 Requests 项目作为他们的 HTTP 工具的首选。最终,我
们可以使用它更快地完成项目,开发人员的时间通常比硬件更昂贵。
行为模式
行为模式旨在通过结构化它们的交互过程来简化类之间的交互。
本节提供了 3 个常用的行为模式的示例,在编写 Python 代码时,你可能需要考虑它们。
• 观察者。
• 访问者。
• 模板。
观察者
观察者(observer)模式用于通知列表中的对象关于被观察组件的状态改变。
使用观察者可以通过从现有代码库中解耦新功能,以可插入的方式在应用程序中添加
特性。事件框架是观察者模式的典型实现,随后会在下面的图中描述。每次事件发生时,
此事件的所有观察者都会收到触发该事件的主题的通知。
事件触发时创建事件。在图形用户界面应用程序中,事件驱动编程(参考 http://en.
wikipedia.org/wiki/Event-driven_programming)经常用于将代码关联到用户操作上。例如,
一个函数可以关联到 MouseMove 事件上,因此每次鼠标移动到窗口时都会调用该函数。
在 GUI 应用程序的情况下,从窗口管理内部解耦代码可以简化很多工作。函数是单独
编写的,然后注册为事件观察器。这种方法存在于 Microsoft 的 MFC 框架的最早版本(参见
http://en.wikipedia.org/wiki/Microsoft_Foundation_Class_Library)以及所有 GUI 开发工具中,例如
Qt 或 GTK。许多框架使用信号(signals)的概念,但它们只是观察者模式的另一种表现形式。
代码也可以产生事件。例如,在将文档存储在数据库中的应用程序中,通过代码可以
提供 DocumentCreated,DocumentModified 和 DocumentDeleted 3 个事件。基
于文档工作的新特性可以将其自身注册为观察器,每次创建,修改或删除文档时,它们就
会收到通知,并执行相应的工作。文档索引器可以在应用程序中以这种方式添加。当然,
这要求所有负责创建,修改或删除文档的代码都会触发事件。但这比在应用程序代码库中
添加索引钩子更容易!流行的 Web 框架 Django 的信号机制就是遵循这种模式。
可以在在类级别上编写实现用于在 Python 中注册观察者的 Event 类,如下所示:
class Event:
_observers = []
def init(self, subject):
self.subject = subject
@classmethod
def register(cls, observer):
if observer not in cls._observers:
cls._observers.append(observer)
@classmethod
def unregister(cls, observer):
if observer in cls._observers:
cls._observers.remove(observer)
@classmethod
def notify(cls, subject):
event = cls(subject)
for observer in cls._observers:
observer(event)
其思想是,观察者们使用 Event 的类方法注册它们自己,并且通过带有触发它们的主题
的事件实例获得通知。下面是一些具体的 Event 子类的示例,一些观察者订阅了它的通知:
class WriteEvent(Event):
def repr(self):
return ‘WriteEvent’
def log(event):
print(
‘{!r} was fired with subject “{}”’
‘’.format(event, event.subject)
)
class AnotherObserver(object):
def call(self, event):
print(
“{!r} trigerred {}'s action”
“”.format(event, self.class.name)
)
WriteEvent.register(log)
WriteEvent.register(AnotherObserver())
下面是使用 WriteEvent.notify()方法触发事件的示例结果如下:
WriteEvent.notify(“something happened”)
WriteEvent was fired with subject “something happened”
WriteEvent trigerred AnotherObserver’s action
这个实现比较简单,仅用于说明的目的。为了使其充分发挥功能,可以通过以下方式
进行改进:
• 允许开发人员更改顺序或事件。
• 使事件对象保存可以保存更多的信息,而不仅仅是主题。
解耦代码是很有趣的,观察者是处理该情况的正确模式。它组件化你的应用程序,并使其
更具可扩展性。如果要使用现有的工具,请尝试 Blinker(参考 https://pythonhosted.org/blinker/)。
它为 Python 对象提供快速并且简单的对象到对象以及广播的信号传递。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值