2

我正在为 uwsgi.it的 api 开发一个 python 客户端,我发现有必要编写接受大量(可选)参数的方法,这些参数将通过 http 请求发送。

最初我想声明用户可以插入哪些参数,因为它们太多了,我认为让用户将列表作为参数而不是让他自由地在字典中插入任何东西会更容易,更安全,我最终像这样:

def alarms(self, container=None, _class=None, color=None,
           vassal=None, level=None, line=None, filename=None, 
           func=None, with_total=None, range=None):
    params = {k: v for k, v in locals().iteritems() if k != 'self' and v}
    if '_class' in params:
        params['class'] = params['_class']
        del params['_class']
    return self.get('alarms', params)

但它非常难看,我真的不喜欢这种处理“_class”参数的方式。因此,我想到的另一种可能性是接受可以包含任何内容(或 **kwargs)的字典,在文档字符串中列出接受的键,然后对输入进行清理。一种可能的方法是声明一个只接受允许的参数的“私有”方法。但随后同样的问题又出现了!有什么建议吗?有这么多参数的方法有什么最佳实践吗?

4

3 回答 3

2

我同意 using**kwargs是一个好主意,您可以使用一组轻松地清理它的键。我使用的是 Python 2.6,所以我没有集合理解,但我的代码应该很容易翻译成更现代的版本。

FWIW,实际上我昨晚很晚才发布了这个程序的一个版本,但后来我认为它应该对错误的参数做一些事情,所以我暂时删除了它。这是修改后的版本。

验证参数.py

#! /usr/bin/env python

''' Validate the keys in kwargs

    Test keys against a container (set, tuple, list) of good keys,
    supplying a value of None for missing keys

    Also, if a key ends with an underscore, strip it.

    Written by PM 2Ring 2014.11.15

    From 
    http://stackoverflow.com/questions/26945235/best-practice-handle-functions-with-lots-of-parameters-and-reserved-names

'''

import sys

def test(**kwargs):
    good_keys = ("container", "class_", "color", 
        "vassal", "level", "line", "filename", 
        "func", "with_total", "range")
    new_kwargs = validate_keys(kwargs, good_keys)
    for t in new_kwargs.items():
        print "%-12s : %r" % t


#def alarms(**kwargs):
    #good_keys = ("container", "class_", "color", 
        #"vassal", "level", "line", "filename", 
        #"func", "with_total", "range")
    #return self.get('alarms', validate_keys(kwargs, good_keys))


def validate_keys(kwargs, good_keys):
    good_keys = set(good_keys)
    bad_keys = set(kwargs.keys()) - good_keys
    if bad_keys:
        bad_keys = ', '.join(bad_keys)
        print >>sys.stderr, "Unknown parameters: %s\n" % bad_keys
        raise KeyError, bad_keys

    new_kwargs = {}  
    for k in good_keys:
        new_kwargs[k.rstrip('_')] = kwargs.get(k, None)
    return new_kwargs


test(color="red", class_="top",
    #bar=1, foo=3,  #Some bad keys
    level=2, func="copy",filename="text.txt")

输出

container    : None
with_total   : None
level        : 2
color        : 'red'
filename     : 'text.txt'
vassal       : None
range        : None
func         : 'copy'
line         : None
class        : 'top'
于 2014-11-15T13:59:32.823 回答
1

当一个方法开始需要许多输入时,要考虑的一种软件设计实践是声明一个包含每个输入值的属性的特殊类,然后您可以将其实例化并与其使用分开填充。这样,您只需将单个引用传递给您的方法签名(封装类),而不是对每个属性的引用。随着对象模型的增长,您甚至可以添加构建器和验证方法来帮助您轻松生成新类并在需要时验证它的属性。

如何在 Python 中定义一个类

此外,将设计模式和 SOLID 设计原则视为改进代码形式、功能和可维护性的方法。深入熟悉这些模式,您将拥有真正提升游戏水平并从软件程序员转变为主管或工程师所需的知识。

http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29

http://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29

http://en.wikipedia.org/wiki/Software_design_pattern

于 2014-11-15T14:58:30.367 回答
1

整理逻辑可以做的一件事是将您的 dict 理解更改为:

params = {k.strip("_"): v for k, v in locals().iteritems() if k != 'self' and v is not None}
#          ^^^^^^^^^^^

然后你不需要对类做任何事情;另外,我可能会使用class_赞成_class,因为后者表示参数是“私有的”,但前者通常暗示“我需要使用关键字作为标识符”

于 2014-11-15T14:43:40.847 回答