【问题标题】:Python function parameter: tuple/listPython函数参数:元组/列表
【发布时间】:2010-11-17 20:01:32
【问题描述】:

我的函数需要一个列表或元组作为参数。它并不关心它是什么,它所做的只是将它传递给另一个接受列表或元组的函数:

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 列出来使其工作。但它并不整洁。

有没有更好的方法呢?当然,我不能强迫调用者总是传递一个元组,因为它只是转移给他们工作。

【问题讨论】:

  • 如果其他函数接受任何一个,我都会向它发送一个元组,因为它会更快地为您工作。那么tuple(x) + ('a',) 有什么不好的地方呢?
  • 元组在实现中是否更快?
  • 从字符串和数字文字构造元组比构造列表更快。更重要的是,tuple(x) 只返回 x 如果它已经是一个元组,而 list(x) 复制 x 即使它已经是一个列表。因此,通过使用元组,您可以减少一半输入案例的大部分工作。
  • +1:关于元组与列表的好点。

标签: python list coding-style tuples


【解决方案1】:

如果another_func 只是想要一个可迭代对象,您可以将itertools.chain(x,'a') 传递给它。

【讨论】:

  • @max 没有复制,所以非常快。它可能是最有效的 Python 解决方案。
【解决方案2】:

改变另一个函数来接受参数列表怎么样?

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

【讨论】:

  • 如果 another_func 需要多个受同一问题影响的列表参数,或者它已经有一个(不相关的)*x 参数,该怎么办?
  • @max:答案是一样的。修复其他功能。
  • 必须在函数的界面中更改一些内容
  • @S.Lott:我现在真的很困惑。如果another_func 需要两个列表,为什么它是一个糟糕的设计?比如说,一个列表是“要打印的列的列表或元组”,另一个是“要从打印中排除的行的列表或元组”。我应该如何以及为什么要更改其界面?
  • @max:元素数量不定的元组是设计错误。元组通常用于确定数量的元素;元素的数量通常由问题域 (x,y) 坐标、(r,g,b) 颜色等固定。“可变大小”元组根本不合适。它应该是一个列表。修复函数以使用列表。修复功能。 “可变长度”或“不定长度”元组是错误的。不要支持他们。修复它们。
【解决方案3】:

怎么样:

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

编辑: 重读问题,我认为这更符合您的要求(argx 的使用有点混乱):

tuple(arg) + ('a',)

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

【讨论】:

  • extend 返回None,因为它会改变列表。
  • @max 我最初有 "['a'].extend(x)" 这是一个基本上没用的语句,因为正如 delnan 指出的那样,extend 返回 None
【解决方案4】:
def f(*args):
    print args

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

a(1, 2, 3)

输出:

(1, 2, 3, 'a')

【讨论】:

  • f(*(tuple(args)+('a',))更好
【解决方案5】:

如果一个迭代器足够了,你可以使用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 消耗所有大部分 的可迭代对象,那么转换@987654330 会更简单@ 到 tuplelist

【讨论】:

  • +1 用于澄清迭代器的倒带。就我而言,可迭代就足够了;我想对于序列情况,我将按照@aaronasterling 的建议强制转换为元组
【解决方案6】:

我的建议:

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

虽然这不是很有效,但如果你打算改变可变的东西,你最好传递它们。

【讨论】:

  • 你能澄清一下吗?为什么这没有效率?
  • @max 效率不高,因为它复制整个列表只是为了添加单个项目。
【解决方案7】:

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

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】:

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

    from itertools import chain
    
    def func(iterable):
        another_func(chain(iterable, ('a',)))
    

    【讨论】:

      【解决方案9】:

      我会说圣地亚哥莱齐卡的回答

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

      是最好的,因为它是最简单的。 (无需导入 itertools 的东西并使用可读性差的链调用)。但仅当您期望 t 很小时才使用它。如果 t 可能很大,您应该使用其他解决方案之一。

      【讨论】:

        猜你喜欢
        • 2012-08-06
        • 2012-04-16
        • 2019-05-20
        • 2021-12-06
        • 2015-01-05
        • 2020-04-27
        • 1970-01-01
        • 1970-01-01
        • 2019-02-23
        相关资源
        最近更新 更多