编写通用的getattr()并根据attr名称填充方法参数 - python

我正在尝试为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', 'resources', 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, verb, obj_type)
    raise AttributeError

python大神给出的解决方案

我不太确定您的代码实际上在做什么,但是从简单的角度来看,我想捕获通用调用,例如publisher.new_resources( [] ),它会自动生成对_pub_wrapper(new, resources, [])或低于_pub(...)的调用。

这是一个工作示例:

class Test:    
    def _pub_wrapper(self, verb, obj_type, id_list):
        print "  Called _pub_wrapper(" , verb, ", ", obj_type, ", ", id_list, ")"
        ids = [str(i) for i in id_list]
        self._pub(ids, '{0}.{1}'.format(verb,
                                        obj_type.lower()))

    def _pub(self, ids, something):
        print "    Called _pub( ", self, ", ", ids, ", ", 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=", verb, ", obj_type=", obj_type, ", args=",  args, ", kwargs=", kwargs
                print "Within wrapper: ", verb, ", ", obj_type, ", ",  args
                return self._pub_wrapper(verb, obj_type, args[0])
            return wrapper
        raise AttributeError

    """        
    def __getattr__(self, item):
        if item in ['new_resources', 'changed_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: ", verb, ", ", obj_type, ", ",  args[0]
                return self._pub_wrapper(verb, obj_type, args[0])
            return wrapper
        raise AttributeError
    """

    def fake_new_resources(self, id_list):
        self._pub_wrapper('new', 'resources', 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 ,  resources ,  [] )
    Called _pub(  <__main__.Test instance at 0x1c366c> ,  [] ,  new.resources )
New tries
Within wrapper: verb= new , obj_type= resources , args= ([],) , kwargs= {}
  Called _pub_wrapper( new ,  resources ,  [] )
    Called _pub(  <__main__.Test instance at 0x1c366c> ,  [] ,  new.resources )
Within wrapper: verb= changed , obj_type= banks , args= ([],) , kwargs= {}
  Called _pub_wrapper( changed ,  banks ,  [] )
    Called _pub(  <__main__.Test instance at 0x1c366c> ,  [] ,  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> ,  ['hi', 'bye'] ,  deleted.items )

代码注释

您非常接近,但是遇到了一些与您的define_verb_and_type()以及与此相关的问题。我对本节进行了一些简化,并增加了调试打印语句的负载。目前,我只在线编码,所以我没有一个好的调试器,因此我使用print进行调试。

我所做的一个更改是,我没有对item in [ ... list ...]进行测试,而是将其拆分,然后对实际的verbobj_type进行了测试。您甚至可能希望放弃obj_type的测试。保留对注释框中的列表进行的工作版本测试。

我与您的代码有关的一个问题是使用_pub_wrapperid_list。我不太清楚您要在此处实现的目标,并且有点希望将其作为实例变量或以其他方式查看此列表的添加/删除。

我还添加了一个新示例来显示命名和未命名的参数。前者出现在kwargs参数中,而后者出现在args参数中。

换句话说,我不太了解我是否正确理解了您的问题,以及您希望我们审查什么代码。但是,我在此处的答案中提供的代码确实提供了所需的通用调用方法,并有望帮助您进行编码项目。

用大写字母拆分字符串,但忽略AAA Python Regex - python

我的正则表达式:vendor = "MyNameIsJoe. I'mWorkerInAAAinc." ven = re.split(r'(?<=[a-z])[A-Z]|[A-Z](?=[a-z])', vendor) 以大写字母分割字符串,例如:'我的名字是乔。 I'mWorkerInAAAinc”变成…

Python:同时在for循环中添加到列表列表 - python

我想用for循环外的0索引值创建一个新列表,然后使用for循环添加到相同的列表。我的玩具示例是:import random data = ['t1', 't2', 't3'] masterlist = [['col1', 'animal1', 'an…

在Flask中测试文件上传 - python

我在Flask集成测试中使用Flask-Testing。我有一个表单,该表单具有我要为其编写测试的徽标的文件上传,但是我不断收到错误消息:TypeError: 'str' does not support the buffer interface。我正在使用Python3。我找到的最接近的答案是this,但是它对我不起作用。这是我的许多尝…

在熊猫中,如何从单词列表或单词集中选择数据框中的短语? - python

在Python3和熊猫中,我具有数据框:df_projetos_api_final.info() <class 'pandas.core.frame.DataFrame'> Int64Index: 93631 entries, 1 to 93667 Data columns (total 21 columns): AnoMat…

在Python中迭代OrderedDict - python

我有以下OrderedDict:OrderedDict([('r', 1), ('s', 1), ('a', 1), ('n', 1), ('y', 1)]) 实际上,这表示单词中字母的出现频率。第一步-我将使用最后两个元素来创建一个这样的联合元组; pair…