|
|
|
|
移动端

2.2.3 装饰器(2)

《Python高级编程(第2版)》第2章语法最佳实践——类级别以下,本章将介绍现在这门语言的语法中最重要的元素,以及它们的使用技巧。本节为大家介绍装饰器。

作者:张亮/阿信 译来源:人民邮电出版社|2018-01-29 18:30

【新品产上线啦】51CTO播客,随时随地,碎片化学习

2.2.3 装饰器(2)

如果我们在Python交互式会话中查看function _ with _ important _ docstring(),会注意到它已经失去了原始名称和文档字符串:

  1. >>> function_with_important_docstring.__name__  
  2. 'wrapped'  
  3. >>> function_with_important_docstring.__doc__  
  4. '包装函数内部文档。' 

解决这个问题的正确方法,就是使用functools模块内置的wraps()装饰器:

  1. from functools import wraps  
  2.  
  3. def preserving_decorator(function):  
  4.     @wraps(function)  
  5.     def wrapped(*args, **kwargs):  
  6.         """包装函数内部文档。"""  
  7.         return function(*args, **kwargs)  
  8.     return wrapped  
  9.  
  10. @preserving_decorator  
  11. def function_with_important_docstring():  
  12.     """这是我们想要保存的重要文档字符串。""" 

这样定义的装饰器可以保存重要的函数元数据:

  1. >>> function_with_important_docstring.__name__  
  2. 'function_with_important_docstring.'  
  3. >>> function_with_important_docstring.__doc__  
  4. '这是我们想要保存的重要文档字符串。' 

2.用法和有用的例子

由于装饰器在模块被首次读取时由解释器来加载,所以它们的使用应受限于通用的包装器(wrapper)。如果装饰器与方法的类或所增强的函数签名绑定,那么应该将其重构为常规的可调用对象,以避免复杂性。在任何情况下,装饰器在处理API时,一个好的做法是将它们聚集在一个易于维护的模块中。

常见的装饰器模式如下所示。

参数检查。

缓存。

代理。

上下文提供者。

(1)参数检查

检查函数接受或返回的参数,在特定上下文中执行时可能有用。举个例子,如果一个函数要通过XML-RPC来调用,那么Python无法像静态语言那样直接提供其完整签名。当XML-RPC客户端请求函数签名时,就需要用这个功能来提供内省能力。

XML-RPC协议

XML-RPC协议是一种轻量级的远程过程调用(Remote Procedure Call)协议,通过HTTP使用XML对调用进行编码。对于简单的客户端-服务器交换,通常使用这种协议而不是SOAP。SOAP提供了列出所有可调用函数的页面(WSDL),XML-RPC与之不同,并没有可用函数的目录。该协议提出了一个扩展,可以用来发现服务器API,Python的xmlrpc模块实现了这一扩展(参见https://docs.python.org/3/library/xmlrpc.server.html)。

自定义装饰器可以提供这种类型的签名,并确保输入和输出代表自定义的签名参数:

  1. rpc_info = {}  
  2.  
  3. def xmlrpc(in_=(), out=(type(None),)):  
  4.     def _xmlrpc(function):  
  5.         # 注册签名  
  6.         func_name = function.__name__  
  7.         rpc_info[func_name] = (in_, out)  
  8.         def _check_types(elements, types):  
  9.             """用来检查类型的子函数。"""  
  10.             if len(elements) != len(types):  
  11.                 raise TypeError('argument count is wrong')  
  12.             typed = enumerate(zip(elements, types))  
  13.             for index, couple in typed:  
  14.                 arg, of_the_right_type = couple 
  15.                 if isinstance(arg, of_the_right_type):  
  16.                     continue  
  17.                 raise TypeError(  
  18.                     'arg #%d should be %s' % (index,  
  19.                       of_the_right_type))  
  20.  
  21.         # 包装过的函数  
  22.         def __xmlrpc(*args):  # 没有允许的关键词  
  23.             # 检查输入的内容  
  24.             checkable_args = args[1:]  # 去掉self  
  25.             _check_types(checkable_args, in_)  
  26.             # 运行函数  
  27.             res = function(*args)  
  28.             # 检查输出的内容  
  29.             if not type(res) in (tuple, list):  
  30.                 checkable_res = (res,)  
  31.             else:  
  32.                 checkable_res = res  
  33.             _check_types(checkable_res, out)  
  34.  
  35.             # 函数及其类型检查成功  
  36.             return res  
  37.         return __xmlrpc  
  38.     return _xmlrpc 

喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书频道活动讨论群:365934973

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

鸟哥的Linux私房菜——服务器架设篇(第二版)

本书是对连续三年蝉联畅销书排行榜前10名的《Linux鸟哥私房菜——服务器架设篇》的升级版,新版本根据目前服务器与网络环境做了大幅度修订...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊