回复真多,插句嘴:我认为短而直观的实现总是更为优雅。Python中提供了这个功能,如果你认为用它实现最简单,就不要怀疑地去使用它。
例如我在YUI里就用了getattr:
https://bitbucket.org/keakon/yui/src/4adaf38a3581/yui.py#cl-1272web.py也用了这种方法:
https://github.com/webpy/webpy/blob/master/web/application.py#L633否则得像webapp一样写很多if..else:
http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/webapp/__init__.py?r=142#514metaclass和decorator我一般只用来隐藏实现,让使用者无需关注其内部的实现。而现在的问题是你开放的这些接口本来就是用来调用的,不应该由被调用者强行注入调用者。
这也是我觉得用decorator来标记一个handler的不妥之处:传统的url mapping方式你可以很一目了然地知道哪些url映射到哪个handler了;而像Uliweb那样写个@
expose的话,你得找到所有的handler才能确定这些映射关系,并且还得关注handler的定义顺序和import的顺序。
而这一切并没有带给你任何好处:逻辑更复杂了,阅读更困难了,维护更吃力了。
最后说下那个help的例子,你不觉得使用decorator的实现导致help函数与其他函数之间的耦合度增加了么?
明明其他函数已经开放了__doc__这个属性了,却还要强迫它们维护help函数所需的_actions列表。
如果定义一个Helper类,遍历自身的方法,用getattr取它们的__doc__,就可以少写一个函数、一个列表和多处@
action。并且,如果这个类被继承了的话,扩展它的人也不需要写@
action来保证help()仍能正常工作。假如你哪天觉得action这个名字不好,需要重命名时,也不需要各处去查找替换@
action。
当然,这个例子如果用metaclass实现的话耦合度没有这么高。但在继承时如果不想展示子类的某几个方法,却发现子类的metaclass必须继承父类的metaclass;而如果有多重继承和多个元类则会更复杂。
虽然这种情况很极端,但你不觉得元类会把实现变得更加抽象么?回过头来想想,它本来不是个很简单的反射就直截了当能完成的事么?