【问题标题】:Pythonic way to pass around many arguments传递许多参数的 Pythonic 方式
【发布时间】:2014-02-03 12:35:55
【问题描述】:

我正在开发一个包含子包和每个子包中的多个模块的包。 大多数函数需要在“主”函数中启动的几个参数(~10)。通常,所有参数都传递给从函数内部调用的方法。传递这些参数的最佳方式是什么?

考虑以下场景:

def func(arg1, arg2, ...., argn):
  do something  
  ext_method(arg1, arg3,...argk) # Note: all the arguments are not passed to ext_method
  cleanup  

PS:函数嵌套可以很深(比如从 main 函数开始大约 10-12 个函数)。 我考虑了两种选择:

  1. 检查方法:用所有参数构造主函数中所有参数的字典。调用函数:使用 inspect 包中的方法获取其 argspec,并从“全局”参数字典中过滤掉不必要的参数。它看起来像下面的 sn-p。

    args = {arg1: obj1, arg2:obj2,...}  
    req_args = dict([(k, v) for k, v in args.items() if k in inspect.getargspec(ext_method).args])
    
  2. 键值方法:ext_method() 使用参数键值对调用

    ext_method(arg1=val1, arg3=val3,...,argk=valk)
    

我发现第二种方法无效,因为随着更多功能添加到包中,更改ext_method() 的签名并不容易。方法 1 是不是更好的选择?

【问题讨论】:

  • 如果您有许多共享状态的函数,使用类可能是一个不错的解决方案。

标签: python arguments


【解决方案1】:

更多更好的选择:

  1. **kwargs 添加到您的函数中并忽略额外的参数:

    ex_method(arg1, arg2, **kw)
    
  2. 传递一个带有所有参数作为属性的对象; namedtuple class 在这里是理想的。每个函数只使用它需要的那些属性。

我会选择后者。停止移动 10 个参数,开始只传递 一个

更好的是,如果所有这些操作都与这些参数所代表的数据真正耦合,也许您应该改用一个类:

class SomeConcept(object):
    def __init__(self, arg1, arg2, arg3, .., argN):
        self.arg1 = arg1
        # ... etc.

    def operation1(self, external_argument):
        # use `self` attributes, return something.

而不是所有那些单独的功能。

【讨论】:

  • 对此进行扩展:如果数据非常紧密地耦合在一起,则可能值得定义一个自己的类(或扩展namedtuple 类)并将上述函数作为方法类。
  • 我也会使用一个命名元组。谁在乎是否所有方法都没有使用一些字段?我很确定在 Code Complete 书中有一个这样的例子。
【解决方案2】:

要传递多个参数,请使用* 运算符和** 运算符。

def foo(*arg, **karg):
    print arg, karg

* 运算符将所有有序参数打包在其中,** 运算符将所有不匹配的键参数打包在其中。

例如:

def foo(a, *arg):
    return a, arg

foo(1,2,3)
>> (1, [2, 3])
foo(1)
>> (1, [])

对于关键参数,它的工作方式相同,

def foo(a=1, b=2, **kargs):
    return a, b, kargs

foo(2, c=10, b=23)
>> (2, 23, {'c': 10})

然后你可以把它们混合起来,那些特殊的情况总是在签名的末尾,像这样:

def foo(a, c, d=4, *arg, **karg):
    return a, c, d, arg, karg

foo(1, 2)
>> (1, 2, 4, [], {})

foo(1,2,3)
>> (1, 2, 3, [], {})

foo(1, 2, 3, 4, 5)
>> (1, 2, 3, [4, 5], {})

foo(1, 2, h=2, f=3, d=4, j=3)
>> (1, 2, 4, [], {'h': 2, 'f': 3, 'j': 3})

foo(1,2,3,4,5, o=2)
>> (1, 2, 3, [4 ,5], {'o': 2})

如果您想将 dict 作为参数或参数列表传递给函数,您也可以使用这些运算符:

a = [1,2,3]
b = {'c': 1, 'd': 3}

def foo(a, b, *arg, **karg):
    return a, b, arg, karg

foo(*a, **b)
>> (1, 2, [3], {'c': 1, 'd': 3})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-26
    相关资源
    最近更新 更多