用装饰器注册 Python 函数 Home » 编程开发 » 用装饰器注册 Python 函数 注册回调函数应该是开发中很常见的一种行为。这在 Python 中通常通过装饰器来实现,看起来比较漂亮: flaskr.py @app.route("/") def home(): return "It works." 但是这种用法常常带来一种隐藏的“惊讶”,比如说: admin_menu.py @permission(["manager", "developer"]) @app.route("/admin") def admin_menu(): return render_template("admin/menu.html") 这个 @permission 根本不会生效,因为在它装饰 admin_menu 之前,admin_menu 就已经被注册到 app 里了。最终我们执行的是未经过装饰的函数。 类似的陷阱还有可能出现在“猴子补丁”使用的场景。比如下面这段代码将一系列 filter 注册到一个对象中: filter_manager.py class FilterManager(object): """The filter registry center.""" def __init__(self): self._filters = {} def register(self, name): def decorator(func): self._filters[name] = func return func return decorator def filter(self, type_name, value): return self._filters[type_name](value) filter_manager = FilterManager() @filter_manager.register("datetime") def datetime_filter(dt): dt.strftime("%Y-%m-%d %H:%M") 看起来似乎很漂亮,但是如果我在写单元测试的时候,希望用一个 Stub 来取代 datetime_filter ,就会小小惊讶一下: test_filter_manager.py from datetime import datetime from mock import patch from filter_manager import filter_manager, datetime_filter @patch("filter_manager.datetime_filter") def test_datetime_filter(): filter_manager.filter("datetime", datetime.utcnow()) assert datetime_filter.called 说到底还是用装饰器注册函数,不是 Lazy Binding 的。 这是我个人感觉 Python 的装饰器使用中比较违反直觉的一个地方。虽然装饰器这种看上去很像“声明”的语法很酷,却也很 implicit 。当然因为装饰器的这种用法实在太流行,很多 Python 开发者已经具备了绕过这个陷阱的技能了(Orz,小白和非小白的区别之一)。但是我还是觉得这种东西需要开发者用经验去绕过的,并不符合我比较认同的最小惊讶原则。 所以…… 我可能还是更喜欢用 Qualified Name 来引用要注册的函数,以实现真正的 Lazy Binding: def import_object(qualname): try: from werkzeug.utils import import_string except ImportError: from importlib import import_module module_name, object_name = qualname.rsplit(".", 1) module = import_module(module_name) return getattr(module, object_name) else: return import_string(qualname)def get_qualname(o): return getattr(o, "__qualname__", "%s.%s" % (o.__module__, o.__name__))class FilterManager(object): """The filter registry center.""" def __init__(self): self._filters_qualname = {} def register(self, name): def decorator(func): self._filters_qualname[name] = get_qualname(func) return func return decorator def filter(self, type_name, value): qualname = self._filters_qualname[type_name] func = import_object(qualname) return func(value) 原文地址:用装饰器注册 Python 函数, 感谢原作者分享。 从此便踏上征途,也许会孤独一程。 相关文章: 华为手机终端云服务抽奖 App Store下架app怎么安装更新 类似芝士超人的app 类似芝士超人的答题软件 类似芝士超人的游戏介绍 怎样在手机上赚零花钱 赚零花钱的软件哪个好 拍照查花软件叫什么 三款识花神器App评测 小米商店是干什么的?到底是不是小米公司? 借款哪个平台最安全可靠利息低(十大靠谱的网贷平台) 如何在台湾虾皮注册本土账号?本土账号发货步骤解析 日本直播平台哪个好?最火日本直播app排行 亚马逊卖家app叫什么名字?app会造成关联吗? 你感兴趣的文章: windows10如何设置字体大小 windows10如何设置字体大小方法介绍 IIS7某种情况上无法保存session 跨境电商独立站有哪些推广途径?如何有效推广? 小兵安装包制作工具安装教程详解 C++找出字符串中出现最多的字符和次数,时间复杂度小于O(n^2) Java知识积累——String引用的判断问题 标签云: 亚洲高清电影在线, 免费高清电影, 八戒影院夜间, 八戒电影最新大片, 出轨在线电影, 午夜电影院, 在线影院a1166, 在线电影院, 在线观看美剧下载, 日本爱情电影, 日韩高清电影在线, 电影天堂网, 直播盒子app, 聚合直播, 高清美剧, 高清美剧在线观看 EhViewer-E站, E站, E站绿色版, qqmulu.com, qq目录网, qq网站目录,