Pythonic way to pass around many arguments

左心房为你撑大大i 提交于 2020-01-13 10:17:09

问题


I'm working on a package that contains subpackages and several modules within each subpackage. Most of the functions need several arguments (~10) that are initiated in the "main" function. Usually, all the arguments are passed to methods that are called from within a function. What is the best way to pass around these parameters ?

Consider the following scenario:

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

PS: Function nesting can go quite deep (say around 10-12 functions starting from main function). I considered two alternatives:

  1. Inspect method: Construct a dict of all the arguments in the main function with all the arguments. To call a function: Get its argspec using the method in inspect package, and filter out unnecessary arguments from the "global" arguments dict. It looks something like the below snippet.

    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. key-value method: ext_method() is called using argument key-value pairs

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

I find the second method to be ineffective because its not easy to change the signature of ext_method() as more features are added to the package. Is method 1 a better alternative ?


回答1:


More, better options:

  1. Add **kwargs to your functions and ignore extra arguments:

    ex_method(arg1, arg2, **kw)
    
  2. Pass around an object with all arguments as attributes; a namedtuple class would be ideal here. Each function only uses those attributes it needs.

I'd pick the latter. Stop moving around 10 arguments, start passing around just one.

Even better, if all those operations are really coupled to the data those arguments represent, perhaps you should be using a class instead:

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

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

instead of all those separate functions.




回答2:


to pass multiple arguments, use the * operator and ** operator.

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

The * operator pack all ordered argument in it, and the ** operator packs all unmatched key argument in it.

For example:

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

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

For key argument it works the same way,

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

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

Then you can mix them up, those sepcial cases are always at the end of the signature like this:

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})

If you want to pass a dict to a function as argument or a list of argument, you can also use those operators:

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})


来源:https://stackoverflow.com/questions/21527610/pythonic-way-to-pass-around-many-arguments

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!