我正在尝试为Pub / Sub类型的应用程序创建一个通用的Python类,其中模型定义为我们拥有的每种类型的资源X指定了三种方法:
new_X changed_X deleted_X
@H_403_8@def _pub_wrapper(self,verb,obj_type,id_list): ids = [str(i) for i in id_list] self._pub(ids,'{0}.{1}'.format(verb,obj_type.lower()))
@H_403_8@def new_resources(self,id_list): self._pub_wrapper('new','resources',id_list) def changed_resources(self,id_list): self._pub_wrapper('changed',id_list)
@H_403_8@我试图找到一个更好的模式,进一步抽象,这样我就不必手写这些单行方法了.因为方法名称映射到我的pub / sub系统中的动词/类型,所以我想的是(伪代码可以遵循):
def __getattr__(self,item): if name in [whitelist of approved methods]: return ??? Some sort of partially defined version of self._pub_wrapper,with verb and obj_type filled in from parsing item ??? raise AttributeError()
@H_403_8@publisher.new_resources([]) publisher.new_items([]) publisher.new_banks([])
@H_403_8@没有我必须手动编码这些方法…有一个优雅的方法来做到这一点?我想也许我可以用__getattr__周围的装饰器来做,但不太确定如何返回一个装饰方法.试过以下,但从未调用self._pub_wrapper()方法.
def define_verb_and_type(*args,**kwargs): def wrap(func): def wrapped_func(*args): return func(*args,verb=kwargs['verb'],obj_type=kwargs['obj_type']) return wrapped_func return wrap def __getattr__(self,item): if item in ['new_resources','changed_resources','deleted_resources']: verb = item.split('_')[0] obj_type = item.split('_')[-1] return define_verb_and_type(self._pub_wrapper,obj_type) raise AttributeError
@H_403_8@
最佳答案
我不太清楚你的代码实际上在做什么,但从简单的角度来看,我得到你想要捕获泛型调用,比如publisher.new_resources([]),它会自动生成对_pub_wrapper的调用(new,resources,[])或_pub(…)下面的一个.
这是一个工作示例:
class Test: def _pub_wrapper(self,id_list): print " Called _pub_wrapper(",",id_list,")" ids = [str(i) for i in id_list] self._pub(ids,obj_type.lower())) def _pub(self,ids,something): print " Called _pub( ",self,something,")" def __getattr__(self,item): verb = item.split('_')[0] obj_type = item.split('_')[-1] if verb in ['new','changed','deleted'] and \ obj_type in ['resources','items','banks']: def wrapper(*args,**kwargs): print "Within wrapper: verb=",obj_type=",args=",args,kwargs=",kwargs print "Within wrapper: ",args return self._pub_wrapper(verb,args[0]) return wrapper raise AttributeError """ def __getattr__(self,item): if item in ['new_resources','deleted_resources','changed_banks']: verb = item.split('_')[0] obj_type = item.split('_')[-1] print verb," vs ",obj_type def wrapper(*args): print "Within wrapper: ",args[0] return self._pub_wrapper(verb,args[0]) return wrapper raise AttributeError """ def fake_new_resources(self,id_list): self._pub_wrapper('new',id_list) t = Test() print "Faking it... " t.fake_new_resources([]) print "New tries" t.new_resources([]) t.changed_banks([]) t.deleted_items(["hi","bye"],4,your=23,mine=42)
@H_403_8@Faking it... Called _pub_wrapper( new,[] ) Called _pub( <__main__.Test instance at 0x1c366c>,[],new.resources ) New tries Within wrapper: verb= new,obj_type= resources,args= ([],),kwargs= {} Called _pub_wrapper( new,new.resources ) Within wrapper: verb= changed,obj_type= banks,kwargs= {} Called _pub_wrapper( changed,banks,changed.banks ) Within wrapper: verb= deleted,obj_type= items,args= (['hi','bye'],4),kwargs= {'your': 23,'mine': 42} Called _pub_wrapper( deleted,items,['hi','bye'] ) Called _pub( <__main__.Test instance at 0x1c366c>,deleted.items )
@H_403_8@你非常接近,但有一些与你的define_verb_and_type()相关的问题,以及调用它.我稍微简化了这一部分,并添加了大量的调试打印语句.目前我只在线编码,所以我没有一个好的调试器,因此我使用print进行调试.
我做的一个改变是,不是测试[… list …]中的项目,而是在之前拆分项目,并测试实际的动词和obj_type.你甚至可能想要放弃obj_type的测试.保持对注释块中的列表进行工作版本测试.
我与你的代码有关的一个问题是在你使用id_list的_pub_wrapper中.我不太明白你想要在这里实现什么,并且有点期望这可能是一个实例变量,或者看到添加/删除到这个列表.
我还添加了一个新示例来显示命名和未命名的参数.前者存在于kwargs参数中,而后者存在于args参数中.
换句话说,如果我正确理解你的问题,以及你希望我们审查哪些代码,我就不太了解.但是我的答案中提供的代码确实提供了您想要的通用调用方法,并希望能帮助您在编码项目中取得进展.