2010-11-17 136 views
6

我的函数需要一个列表或元组作为参数。它并不真正关心它是,它所做的只是把它传递给可以接受一个列表或元组的另一个功能:Python函数参数:元组/列表

def func(arg): # arg is tuple or list 
    another_func(x) 
    # do other stuff here 

现在我需要稍微修改的功能,来处理额外的元素:

def func(arg): #arg is tuple or list 
    another_func(x + ['a']) 
    # etc 

不幸的是,这是行不通的:如果arg是元组,我必须说x + ('a',)

很明显,我可以通过强制arg列表工作。但它并不整齐。

有没有更好的方法呢?当然,我不能强迫呼叫者总是通过一个元组,因为它只是转移到他们工作。

+0

如果其他函数接受或者我会发送它一个元组,因为它会更快地处理。那么'tuple(x)+('a',)''不完整? – aaronasterling 2010-11-17 20:08:38

+0

元组实现速度更快吗? – max 2010-11-17 20:40:27

+2

从字符串和数字文字构造一个元组比构建一个列表要快。更重要的是,如果tuple(x)已经是一个元组,那么'tuple(x)'只返回'x',而'list(x)'拷贝'x'即使它已经是一个列表。因此,通过使用元组,可以将大部分工作切分为一半的输入案例。 – aaronasterling 2010-11-17 20:49:43

回答

7

如果another_func只是想要一个迭代你可以通过itertools.chain(x,'a')它。

+0

+1我喜欢这样,但速度快吗? – max 2010-11-17 20:45:28

+0

@max没有复制,因此速度非常快。这可能是最有效的Python解决方案。 – 2010-11-17 21:14:33

3

怎么样:

l = ['a'] 
l.extend(x) 

编辑: 重读的问题,我觉得这是更你想要什么(使用argx是有点混乱):

tuple(arg) + ('a',) 

正如其他人所说,这可能不是最有效的方式,但它非常清楚。如果你的元组/列表很小,我可能会使用这个不太清晰的解决方案,因为性能影响可以忽略不计。如果您的清单很大,请使用更高效的解决方案。

+0

'extend'返回'None',因为它会改变列表。 – delnan 2010-11-17 20:05:08

+0

+1,简单又干净 – slezica 2010-11-17 20:06:38

+0

@delnan:你是什么意思? – max 2010-11-17 21:42:45

4

如何将其他函数改为接受params列表呢?

def func(arg): # arg is tuple or list 
    another_func('a', *x) 
+1

那么another_func需要几个列表参数时受到同一问题的影响,或者它已经有一个(不相关的)* x参数? – max 2010-11-17 21:41:58

+0

+0:很好,但不确定是否可以更改其他功能 – Claudiu 2010-11-17 21:43:29

+0

@max:答案是一样的。修复其他功能。 – 2010-11-17 21:57:44

2
def f(*args): 
    print args 

def a(*args): 
    k = list(args) 
    k.append('a') 
    f(*k) 

a(1, 2, 3) 

输出:

(1, 2, 3, 'a') 
+0

hmm'f(*(tuple(args)+('a',))'是更好的 – Claudiu 2010-11-17 21:44:08

1

我的建议:

def foo(t): 
    bar(list(t) + [other]) 

这是不是很有效,但是,你会更好绕过可变的东西,如果你要成为,好吧,改变它们。

+0

请问您能澄清一下吗?为什么这样做效率不高? – max 2010-11-17 20:44:08

+0

@max它效率不高,因为它复制整个列表只是为了添加一个单一的项目 – 2010-11-17 21:16:39

0

让你的函数接受任何迭代。然后使用itertools.chain将您想要的任何序列添加到迭代器中。

from itertools import chain 

def func(iterable): 
    another_func(chain(iterable, ('a',))) 
1

可以使用迭代传递给第一个函数的类型来构建你传递给第二个内容:

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'] 
2

如果一个迭代是的话,你可以使用itertools.chain,但要知道,如果函数A(第一个被调用)在调用B后迭代遍历该迭代,那么您可能会遇到问题,因为无法重新迭代迭代。在这种情况下,你应该选择一个序列或使用iterable.tee使可迭代的副本:

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 

即使itertools.tee是不是真的那么有效的,如果B消耗所有可迭代的,那么只需将iterable转换为tuplelist即可。

+0

+ 1用于说明迭代器的重绕在我的例子中,iterable已经足够了;我猜测序列的情况下,我只会根据@aaronasterling的建议强迫元组 – max 2010-11-17 21:43:37

0

我会说这样做

def foo(t): 
    bar(list(t) + [other]) 

圣地亚哥Lezica的回答是最好的,因为它是最简单的。 (不需要导入itertools的东西,并使用更少的可读链式调用)。但只有在你希望t很小的时候才能使用它。如果t可能很大,您应该使用其他解决方案之一。