最佳实践:处理具有大量参数和保留名称的函数

时间:2014-11-15 11:18:56

标签: python coding-style input-sanitization

我正在研究u python client for the api的uwsgi.it,我发现有必要编写接受大量(可选)参数的方法,这些参数将通过http请求发送。

最初我想声明用户可以插入哪些参数,因为它们是如此之多,我认为它更容易,更安全,用户可以将列表作为参数而不是让他自由地在dict中插入任何内容我最终得到了这样的东西:

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),列出docstring中接受的键,然后清理输入。一种可能的方法是声明一个只接受允许的参数的“私有”方法。但是再次出现同样的问题!有什么建议吗?有这么多参数的方法的最佳实践吗?

3 个答案:

答案 0 :(得分:2)

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

FWIW,我实际上昨晚发布了这个程序的一个版本,但后来我决定应该对坏参数做些什么,所以我暂时将其删除了。这是修订版。

<强> validate_params.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'

答案 1 :(得分:1)

你可以做的一件事就是整理逻辑就是把你的词汇理解改为:

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

然后你不需要做任何关于课程的事情;此外,我可能会使用class_支持_class,因为后者表明该参数是“私有的”,但前者通常暗示“我需要使用关键字作为标识符“

答案 2 :(得分:1)

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

How to define a class in 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