【问题标题】:Should lists always be converted to tuples?列表是否应该始终转换为元组?
【发布时间】:2021-03-27 16:04:19
【问题描述】:

我正在尝试加强我的“最佳实践”,并且我正在阅读有关列表与元组和内存分配的更多信息,以及如果在程序运行时不会更改列表,您应该如何使用元组.

话虽如此,如果是这种情况,您是否应该(几乎)总是从列表转换为元组?

例如,假设我有这段代码,我正在查看用户输入的 100 种颜色:

with open("colors.txt", "r") as file:
    lst = [line.strip() for line in file.readlines()]

我不打算改变列表。这是否意味着我应该遵循:

tup = tuple(lst)

然后使用tup

我意识到这是一个很小的例子,转换为元组只需要 1 行,但这是最佳做法吗?只是感觉有点笨拙,因为它对我来说是新的。

谢谢!

【问题讨论】:

  • 为什么不直接使用tuple 开头呢? color_tup = tuple(line.strip() for line in file.readlines())
  • tuple(map(str.strip, file))。列表或元组都可以正常工作。
  • 好点@khelwood 因为它只是一个操作,使用map 肯定更好。
  • OP,在这种情况下,“最佳实践”将简单地使用 tuple 开头,如前面的 cmets 中所述。那,并且使用比lst 更好的变量名:D 至于使用list 而不是tuple,它确实取决于您的用例。如果您不打算修改内容,请绝对使用tuple。或者set,如果您不关心订单并且想要强制执行独特的元素(以及恒定的时间成员资格检查!)。
  • 具有相同元素的元组列表之间的内存消耗差异在现代机器上不太可能显着,除非您正在处理真正的大数据。从语义上讲,使用元组表示元素在集合中的位置很重要,例如在('Jane', 'Smith') 'Jane' 是给定名称,'Smith' 是姓氏。在列表中,位置无关紧要:在['red', 'blue', 'yellow'] 中,所有元素都是颜色,在列表中的第一个或最后一个并不重要。

标签: python python-3.x list tuples


【解决方案1】:

我想我会按照 OP 的要求回答。

首先,在您不打算修改集合的情况下,“最佳实践”通常意味着使用tuple,是的。您可以通过简单地避免首先创建 list 来跳过强制转换的“笨拙”:

with open("colors.txt", "r") as f:
    colors = tuple(map(str.strip, f))

感谢@khelwood

或者

tuple(some_expression for item in some_iterable)

对于更复杂的表达式。

正如@snakecharmerb 指出的那样,当元素的顺序很重要时,使用tuple 也是一个好主意。由于tuple 对象是不可变的,因此如果您愿意,将元素放置在tuple 中的顺序是“一成不变的”。这向读者表明,顺序对您的数据极为重要。

对于顺序不重要并且您想强制执行唯一元素的时候,set 是理想的,因为它们仍然是可迭代的,但也有恒定时间成员资格检查,这在某些情况下可能会有所帮助情况。

【讨论】:

    【解决方案2】:

    您可以直接创建元组而不是从列表转换;例如

    tuple(map(str.strip, file))
    

    如果您希望更改序列,请使用列表。如果要确保不能更改序列,请使用元组。如果这两种方法都没有关系,您可以使用任何一种。

    【讨论】:

    • @blorgon 我认为我们的答案不同,足以共存。
    【解决方案3】:

    我不同意元组更好。也许在较旧的 Python 中,答案是不同的,但是对于 Python 3.8.5,这取决于“更好”的含义。

    采取以下措施。

    from sys import getsizeof
    import numpy as np
    
    a = np.array([i for i in range(10000000)])
    b = [i for i in range(10000000)]
    c = tuple([i for i in range(10000000)])
    
    sum_a = np.sum(a)   # timeit 4.04 ms ± 71.2 µs per loop
    sum_b = sum(b)      # timeit 199 ms ± 2.32 ms per loop
    sum_c = sum(c)      # timeit 195 ms ± 2.72 ms per loop
    
    print(f"numpy sum {sum_a} {getsizeof(a)}")
    print(f"list  sum {sum_b} {getsizeof(b)}")
    print(f"tuple sum {sum_c} {getsizeof(c)}")
    

    输出是:

    numpy sum    -2014260032 40000096
    list  sum 49999995000000 81528048
    tuple sum 49999995000000 80000040
    

    因为速度 numpy 是赢家,但是速​​度的提高是以固定长度的数学溢出和错误答案为代价的。所以小心点。

    对于列表和元组,速度通常接近相同。从列表创建元组的成本可能会有所影响,具体取决于您的用例,但是为了速度,我们将它们大致称为等价。

    那么,numpy - 小心,列表还是元组?哪个更漂亮、更明确、更简单、更扁平(参见 PEP20)?为了我的钱,额外的tuple(...) 不那么禅了。

    我没有发现元组是不可变的论点令人信服。鉴于 Python 在键入使用大写字母表示 DONT_CHANGE_MEfeel_free_to_change 作为变量名称方面的一般灵活性更清楚。此建议来自 PEP8 https://www.python.org/dev/peps/pep-0008/#descriptive-naming-styles

    【讨论】:

    • DONT_CHANGE_ME 是一个 可怕 变量名,大写和小写变量名作为一种表示应该和不应该改变的方式是一个糟糕的想法和愚蠢我以前从未听过任何人建议过的约定。 Python 中的大写变量名用于全局变量。在变量名中说“不要改变我”之类的话也是……哈哈。像。您要确保您的事情无法改变,而不仅仅是希望其他人会听您的请求。请参阅 this 帖子了解为什么 tuple 在许多方面都优于 list
    • PS——你是在做一些不必要的工作,先创建一个list,然后再转换为tuple,而你可以只做tuple(range(10000000)),速度是原来的两倍.不过,FWIW,您也可以使用 [*range(10000000)],它的创建速度也大约是沼泽标准理解的两倍。
    • 如果它给你一个无法使用的结果,那么说“numpy 更快”也是一种愚蠢的观点。
    • blorgon - 如果您了解关于 numpy 的这一点,速度改进有用的用例将是壮观
    • 请告知我快速做不正确的事情优于慢慢做正确的事情的情况。
    猜你喜欢
    • 1970-01-01
    • 2011-10-29
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-11
    • 2015-01-30
    • 2011-02-27
    相关资源
    最近更新 更多