我正在尝试为Pub / Sub类型的应用程序创建一个通用的Python类,其中模型定义为我们拥有的每种类型的资源X指定了三种方法:
new_X
changed_X
deleted_X
我已经将代码抽象为单个方法,它接受有关类型和操作的参数:
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()))
但这需要我手工编写每个定义的方法,尽管在一行中,每个方法:
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)
我试图找到一个更好的模式,进一步抽象,这样我就不必手写这些单行方法了.因为方法名称映射到我的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()
这种通用方法理想情况下会捕获如下调用:
publisher.new_resources([])
publisher.new_items([])
publisher.new_banks([])
没有我必须手动编码这些方法…有一个优雅的方法来做到这一点?我想也许我可以用__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
最佳答案
我不太清楚你的代码实际上在做什么,但从简单的角度来看,我得到你想要捕获泛型调用,比如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)
运行它时生成的输出是:
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 )
代码评论
你非常接近,但有一些与你的define_verb_and_type()相关的问题,以及调用它.我稍微简化了这一部分,并添加了大量的调试打印语句.目前我只在线编码,所以我没有一个好的调试器,因此我使用print进行调试.
我做的一个改变是,不是测试[… list …]中的项目,而是在之前拆分项目,并测试实际的动词和obj_type.你甚至可能想要放弃obj_type的测试.保持对注释块中的列表进行工作版本测试.
我与你的代码有关的一个问题是在你使用id_list的_pub_wrapper中.我不太明白你想要在这里实现什么,并且有点期望这可能是一个实例变量,或者看到添加/删除到这个列表.
我还添加了一个新示例来显示命名和未命名的参数.前者存在于kwargs参数中,而后者存在于args参数中.
换句话说,如果我正确理解你的问题,以及你希望我们审查哪些代码,我就不太了解.但是我的答案中提供的代码确实提供了您想要的通用调用方法,并希望能帮助您在编码项目中取得进展.