问题
My function expects a list or a tuple as a parameter. It doesn't really care which it is, all it does is pass it to another function that accepts either a list or tuple:
def func(arg): # arg is tuple or list
another_func(x)
# do other stuff here
Now I need to modify the function slightly, to process an additional element:
def func(arg): #arg is tuple or list
another_func(x + ['a'])
# etc
Unfortunately this is not going to work: if arg is tuple, I must say x + ('a',)
.
Obviously, I can make it work by coercing arg to list. But it isn't neat.
Is there a better way of doing that? I can't force callers to always pass a tuple, of course, since it simply shifts to work to them.
回答1:
If another_func
just wants a iterable you can pass itertools.chain(x,'a')
to it.
回答2:
What about changing the other function to accept a list of params instead ?
def func(arg): # arg is tuple or list
another_func('a', *x)
回答3:
how about:
l = ['a']
l.extend(x)
Edit:
Re-reading question, I think this is more what you want (the use of arg
and x
was a little confusing):
tuple(arg) + ('a',)
As others have said, this is probably not the most efficient way, but it is very clear. If your tuples/lists are small, I might use this over less clear solutions as the performance hit will be negligible. If your lists are large, use the more efficient solutions.
回答4:
def f(*args):
print args
def a(*args):
k = list(args)
k.append('a')
f(*k)
a(1, 2, 3)
Output:
(1, 2, 3, 'a')
回答5:
If an iterable is enough you can use itertools.chain, but be aware that if function A
(the first one called), also iterates over the iterable after calling B
, then you might have problems since iterables cannot be rewinded. In this case you should opt for a sequence or use iterable.tee to make a copy of the iterable:
import itertools as it
def A(iterable):
iterable, backup = it.tee(iterable)
res = B(it.chain(iterable, 'a'))
#do something with res
for elem in backup:
#do something with elem
def B(iterable):
for elem in iterable:
#do something with elem
Even though itertools.tee
isn't really that efficient if B
consumes all or most of the iterable, at that point it's simpler to just convert iterable
to a tuple
or a list
.
回答6:
My suggestion:
def foo(t):
bar(list(t) + [other])
This is not very efficient though, you'd be better off passing around mutable things if you're going to be, well, mutating them.
回答7:
You can use the type of the iterable passed to the first function to construct what you pass to the second:
from itertools import chain
def func(iterable):
it = iter(iterable)
another_func(type(iterable)(chain(it, ('a',))))
def another_func(arg):
print arg
func((1,2))
# (1, 2, 'a')
func([1,2])
# [1, 2, 'a']
回答8:
Have your function accept any iterable. Then use itertools.chain
to add whatever sequence you want to the iterable.
from itertools import chain
def func(iterable):
another_func(chain(iterable, ('a',)))
回答9:
I'd say Santiago Lezica's answer of doing
def foo(t):
bar(list(t) + [other])
is the best because it is the simplest. (no need to import itertools stuff and use much less readable chain calls). But only use it if you expect t to be small. If t can be large you should use one of the other solutions.
来源:https://stackoverflow.com/questions/4208619/python-function-parameter-tuple-list