问题
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:
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])
key-value method:
ext_method()
is called using argument key-value pairsext_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:
Add
**kwargs
to your functions and ignore extra arguments:ex_method(arg1, arg2, **kw)
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