python:list vs tuple,何时使用?

fly*_*ire 420 python types tuples list

在Python中,何时应该使用列表和何时使用元组?

有时你没有选择权,例如你有

"hello %s you are %s years old" % x
Run Code Online (Sandbox Code Playgroud)

然后x必须是一个元组.

但如果我是设计API并选择数据类型的人,那么指导原则是什么?

jld*_*ont 651

元组本质上是固定大小的,而列表是动态的.
换句话说,a tuple不可变的,而a list可变的.

  1. 您无法将元素添加到元组.元组没有追加或扩展方法.
  2. 您无法从元组中删除元素.元组没有删除或弹出方法.
  3. 您可以在元组中找到元素,因为这不会更改元组.
  4. 您还可以使用in运算符来检查元组中是否存在元素.

  • 元组比列表更快.如果你要定义一组常量值,那么你将要做的就是迭代它,使用元组而不是列表.

  • 如果您"写保护"不需要更改的数据,它会使您的代码更安全.使用元组而不是列表就像有一个隐含的断言声明,这个数据是常量,并且需要特殊思想(和特定函数)来覆盖它.

  • 一些元组可以用作字典键(特别是包含不可变值的元组,如字符串,数字和其他元组).列表永远不能用作字典键,因为列表不是不可变的.

资料来源:深入研究Python 3

  • "写保护"类比只是到目前为止:元组的成员资格不能改变*但*元组*的可变元素可以*改变:l = list(); t =(l,l); l.append(1) (43认同)
  • @kracekumar:那是因为在你的例子中你首先创建了一个列表,然后把它变成了一个元组.显然它比较慢.看看这个:`$ python -m timeit"for x in xrange(10000):""''.join(['a','b','c','d','e','f' ,'g'])"1000循环,最佳3:1.91毫秒每循环$ python -m timeit"for x in xrange(10000):""''.join(('a','b','c ','d','e','f','g'))"1000循环,最佳3:每循环1.17毫秒" (30认同)
  • 是什么让你认为元组比列表更快? (7认同)
  • 由于编辑被拒绝并且无法将其添加为答案,因此这里是添加更多信息的注释:复制或克隆元组并不像列表或字典那样简单.例如,您可以使用`list2 = list1 [:]`克隆列表.类似地,您也可以使用`dict2 = dict1.copy()`来克隆字典,但元组本身没有该方法.如果需要,可以使用`copy`模块中的`deepcopy`方法. (6认同)
  • @VishnuNarang除了你可以用`tuple2 = tuple1 [:]`克隆一个元组吗?虽然没有必要这样做,因为结果对象既a)不可变,又b)与第一个相同.唯一有意义的是元组有可变子元素,但是无论是字典,列表还是元组,你都必须进行深度复制. (5认同)
  • 元组并不比列表快。在[220]中:t_range = tuple(range(100000))在[221]:99999 in t_range Out [221]:True In [222]:l_range = range(100000)在[223]:99999 in l_range Out [223 ]:True [224]:%% timeit .....:99999 in l_range .....:100个循环,最好3:2.97 ms /循环In [225]:%% timeit ..... :99999 in t_range .....:100循环,最佳3:每个循环3.01毫秒 (2认同)

Ned*_*der 225

对于异构集合,有一种强大的元组文化,类似于你struct在C中使用的元组,并列出了同类集合,类似于你使用数组的集合.但我从来没有像其他答案中提到的可变性问题那样对此进行平衡.可变性对它有影响(你实际上不能改变一个元组),而同质性没有强制执行,因此似乎是一个不那么有趣的区别.

  • 通过比较`struct`的错误特性,你错过了它的语义.当_position具有相关性时,元组很有用 - 最好的例子来自数学中的坐标,它甚至使用相同的语法:`(x,y,z)` (40认同)
  • @GreenAsJade:这就是`collections.namedtuple`的用途(与`dict`不同,唯一的成本是定义`namedtuple`;实例在内存中的大小与同等长的`元组'完全相同,但可以是通过`.name`以及索引访问.`tuple`作为异构轻量级"对象"的经典用例都可以用`collections.namedtuple`替换,但在很多情况下它是不必要的(在`zip上循环)可以解压缩到命名变量,因此不能通过名称访问元组,但是你从不直接使用`tuple`s). (7认同)
  • Arlen:可变点实际上是一个非常糟糕的主意.坚持使用不可变点并创建新点,它们足够便宜.如果您要处理数百万个点,请使用Flyweight模式并保留最近使用的点的缓存. (4认同)
  • @Ned所以,说你想实现一个Point类.你会使用元组或列表来保存x,y,z坐标吗?您可能希望更改值(使用列表),但同时顺序和位置是有意义且一致的(与元组一起使用?). (3认同)
  • 除了可变性,为什么我们不总是使用字典而不是元组?这将带来命名字段的优势,这将使访问单个元素的可读性更高... (2认同)
  • @JohnCowan - 这并不是说它们是一个坏主意 - 而是它们没有意义。点在逻辑上是不可变的,就像整数一样 - 您不会通过加 1 来为 5 分配新值 - 您会得到一个新整数 6。点也是如此,因为它只是两个整数。如果我改变它的值,我并没有改变点的身份——我有一个具有不同身份的不同点。可变对象改变它们的值而不改变它们的标识,但不可变对象的值就是它的标识。 (2认同)
  • @Bachsau 微优化是选择数据结构的错误原因。你应该更好:) (2认同)

tho*_*mad 82

我相信(我并不精通Python),主要区别在于元组是不可变的(在赋值后它不能改变)并且列表是可变的(你可以追加,改变,减去等等) ).

所以,我倾向于让我的元组在分配后不应该改变的东西,我列出的东西可以.

  • 好吧,即使你不打算变异,为什么不使用列表呢? (3认同)
  • @KalEl这篇文章中的一些其他答案解释了为什么人们可能会选择在列表上使用元组. (3认同)

AFo*_*lia 43

它必须是可变的吗?使用列表.它一定不可变吗?使用元组.

否则,这是一个选择问题.

对于异构对象的集合(如地址分为名称,街道,城市,州和邮编),我更喜欢使用元组.它们总是可以轻松升级为命名元组.

同样,如果集合将被迭代,我更喜欢列表.如果它只是一个容纳多个对象的容器,我更喜欢一个元组.

  • 你为什么要使用一个元组,甚至一个命名元组,而不是一个dict? (4认同)
  • 这是唯一的好答案.它陈述了真相,而不仅仅是每个人都知道的可变/不可变的东西. (3认同)
  • 对偏好的一些理由会很好.为什么你喜欢异类对象的元组?如果要迭代,为什么更喜欢列表? (2认同)
  • @GreenAsJade,我知道这很旧了,但原因是,元组仍然是可迭代的,并且顺序很重要(命令不能保证顺序)。 (2认同)

Ama*_*ren 14

您需要决定的第一件事是数据结构是否需要是可变的.如前所述,列表是可变的,元组不是.这也意味着元组可以用于字典键,而列表则不能.

根据我的经验,元组通常用于秩序和位置有意义且一致的地方.例如,在为选择自己的冒险游戏创建数据结构时,我选择使用元组而不是列表,因为元组中的位置是有意义的.以下是该数据结构的一个示例:

pages = {'foyer': {'text' : "some text", 
          'choices' : [('open the door', 'rainbow'),
                     ('go left into the kitchen', 'bottomless pit'),
                     ('stay put','foyer2')]},}
Run Code Online (Sandbox Code Playgroud)

元组中的第一个位置是用户在玩游戏时显示的选项,第二个位置是选择所用页面的键,这对所有页面都是一致的.

元组也比列表更有内存效率,但我不确定这种好处何时变得明显.

另请查看Think Python中列表和元组的章节.

  • +1 - 虽然可变性/不变性是一个重要的考虑因素,具有相关性的位置是_the_主要原因 - 数学甚至对坐标系使用相同的语法:`(x,y,z)` (2认同)

Raf*_*ird 11

但如果我是设计API并选择数据类型的人,那么指导原则是什么?

对于输入参数,最好接受最符合您需求的通用接口.它很少只是一个元组或列表 - 更常见的是序列,可切片甚至可迭代.除非你明确检查输入类型,否则Python的鸭子输入通常是免费的.除非绝对不可避免,否则不要这样做.

对于您生成的数据(输出参数),只返回对您最方便的数据,例如,返回您保留的任何数据类型或帮助函数返回的任何数据类型.

要记住的一件事是避免返回属于您所在州的列表(或任何其他可变的列表),例如

class ThingsKeeper
    def __init__(self):
        self.__things = []

    def things(self):
        return self.__things  #outside objects can now modify your state

    def safer(self):
        return self.__things[:]  #it's copy-on-write, shouldn't hurt performance
Run Code Online (Sandbox Code Playgroud)