使用** kwargs和装饰器来防止重复代码是否可以接受?

时间:2011-10-28 14:52:51

标签: python api decorator

我目前正在python中编写一个api库,我想知道下面的代码是不是太麻烦了:

@accepts('video_id', 'reference_id', 'page_size', 'page_number',
         'get_item_count', 'fields', 'video_fields', 'custom_fields',
         'media_delivery', 'output')
@requires('video_id', 'reference_id')
def find_related_videos(self, **params):
    return ItemCollection(read_request(params))

如果列表中没有任何kwargs传递给方法,accepts装饰器会抛出错误。它还会对某些关键字进行验证。

requires装饰器确保存在这些关键字参数。

方法定义中没有关键字args让我烦恼。但是,必须为每种方法手动构建params字典似乎也很烦人。此外,验证代码对于传递给方法的video_fields参数的每个实例都是相同的,因此我可以从接受装饰器中调用它以避免重复自己。

思想?

4 个答案:

答案 0 :(得分:1)

我肯定会在方法签名中放入必填字段:

def find_related_videos(self, video_id, reference_id, **params):
    params.update({'video_id': video_id, 'reference_id': reference_id})
    return ItemCollection(read_request(params))

如果可能的话,我甚至会修改read_request以获取关键字参数:

def find_related_videos(self, video_id, reference_id, **params):
    return ItemCollection(read_request(video_id=video_id, reference_id=reference_id, **params))

就可接受的参数而言,我个人不会为无效的参数抛出错误 - 我会忽略那些我不需要的错误。

答案 1 :(得分:1)

这个解决方案怎么样?

def check_params(params):
    # Do whatever check you want to do on params
    return dict((k, v) for k, v in params
                if v is not None and k != "self")

def find_related_videos(self, video_id, reference_id, page_size=None,
                        page_number=None, get_item_count=None, fields=None,
                        video_fields=None, custom_fields=None,
                        media_delivery=None, output=None):
    params = check_prams(locals())
    return ItemCollection(read_request(params))

这将为Python检查可接受和必需的参数,同时在check_params()中实现自定义测试。

答案 2 :(得分:0)

我会在没有装饰者的情况下做到这一点。读者更容易遵循没有装饰器的代码执行路径:

required = set(['video_id', 'reference_id'])
acceptable = required.union(set(['page_size', 'page_number', 'get_item_count', 'fields', 'video_fields', 'custom_fields', 'media_delivery', 'output']))

def find_related_videos(self, **params): 
    if not (required.issubset(set(params.keys())) or set(params.keys()).issubset(acceptable)):
        raise Exception("Some exception")
    return ItemCollection(read_request(params))

这会检查所有kwargs的密钥是否在acceptable集合中,并且至少包含required args。

答案 3 :(得分:0)

如果你这样做:

def find_related_videos(self, video_id, reference_id, ...)

然后您仍然可以使用装饰器来检查参数的有效性,并让解释器为您强制执行其余操作。但是有一些权衡取舍。

  • 使用位置参数,您不再允许调用者以任何顺序指定参数。如果您基本上是在阅读字典并传递它,或类似的东西,这可能是一个问题。
  • 编写@accepts(或@validate)装饰器以更一般的方式检查参数的有效性更加困难。它仍然可以通过使用inspect.getargspec函数来完成,之前我做过类似的事情,但它需要一些时间才能使它工作。我的装饰器自动将HTTP GET参数与函数参数匹配是很复杂的,但是它可以工作。