标签归档:tuples

为什么我们需要Python(或任何不可变数据类型)中的元组?

问题:为什么我们需要Python(或任何不可变数据类型)中的元组?

我已经阅读了几本python教程(《 Dive Into Python》,其中之一),以及Python.org上的语言参考-我不明白为什么该语言需要元组。

元组与列表或集合相比没有任何方法,如果我必须将元组转换为集合或列表以对其进行排序,那么首先使用元组的意义是什么?

不变性?

为什么有人会关心变量是否位于与最初分配时不同的内存位置?Python不可变性的全部工作似乎都过分强调了。

在C / C ++中,如果我分配了一个指针并指向一些有效的内存,则在使用该地址之前,只要它不为null,我都不在乎该地址位于何处。

每当我引用该变量时,都不需要知道指针是否仍指向原始地址。我只是检查null并使用(或不使用)。

在Python中,当我分配一个字符串(或元组)并将其分配给x,然后修改该字符串时,为什么我不在乎它是否是原始对象?只要变量指向我的数据,那就很重要。

>>> x='hello'
>>> id(x)
1234567
>>> x='good bye'
>>> id(x)
5432167

x 仍然引用我想要的数据,为什么有人需要关心其ID是相同还是不同?

I’ve read several python tutorials (Dive Into Python, for one), and the language reference on Python.org – I don’t see why the language needs tuples.

Tuples have no methods compared to a list or set, and if I must convert a tuple to a set or list to be able to sort them, what’s the point of using a tuple in the first place?

Immutability?

Why does anyone care if a variable lives at a different place in memory than when it was originally allocated? This whole business of immutability in Python seems to be over emphasized.

In C/C++ if I allocate a pointer and point to some valid memory, I don’t care where the address is located as long as it’s not null before I use it.

Whenever I reference that variable, I don’t need to know if the pointer is still pointing to the original address or not. I just check for null and use it (or not).

In Python, when I allocate a string (or tuple) assign it to x, then modify the string, why do I care if it’s the original object? As long as the variable points to my data, that’s all that matters.

>>> x='hello'
>>> id(x)
1234567
>>> x='good bye'
>>> id(x)
5432167

x still references the data I want, why does anyone need to care if its id is the same or different?


回答 0

  1. 不变的对象可以实现实质性的优化;这大概就是为什么字符串在Java中也是不可变的,它是与Python完全分开但同时开发的,而在真正功能的语言中几乎所有东西都是不可变的。

  2. 特别是在Python中,只有不可变的对象才可以是可哈希的(因此,集合的成员或字典中的键)也是可以哈希的。再次,这种优化提供了优化,但不仅仅是“实质性”(设计存储完全可变对象的体面哈希表是一场噩梦-要么在对哈希进行哈希处理后立即复制所有内容,要么进行检查对象是否哈希的噩梦)自从您上次引用它以来,它已经改变了,它的头变得丑陋。

优化问题示例:

$ python -mtimeit '["fee", "fie", "fo", "fum"]'
1000000 loops, best of 3: 0.432 usec per loop
$ python -mtimeit '("fee", "fie", "fo", "fum")'
10000000 loops, best of 3: 0.0563 usec per loop
  1. immutable objects can allow substantial optimization; this is presumably why strings are also immutable in Java, developed quite separately but about the same time as Python, and just about everything is immutable in truly-functional languages.

  2. in Python in particular, only immutables can be hashable (and, therefore, members of sets, or keys in dictionaries). Again, this afford optimization, but far more than just “substantial” (designing decent hash tables storing completely mutable objects is a nightmare — either you take copies of everything as soon as you hash it, or the nightmare of checking whether the object’s hash has changed since you last took a reference to it rears its ugly head).

Example of optimization issue:

$ python -mtimeit '["fee", "fie", "fo", "fum"]'
1000000 loops, best of 3: 0.432 usec per loop
$ python -mtimeit '("fee", "fie", "fo", "fum")'
10000000 loops, best of 3: 0.0563 usec per loop

回答 1

上面的答案都没有指出元组与列表的真正问题,许多Python新手似乎还没有完全理解。

元组和列表有不同的用途。列表存储同类数据。您可以并且应该有这样的列表:

["Bob", "Joe", "John", "Sam"]

正确使用列表的原因是因为这些列表都是同类型的数据,尤其是人们的名字。但采取这样的清单:

["Billy", "Bob", "Joe", 42]

该清单是一个人的全名和年龄。那不是一种数据。存储该信息的正确方法是在元组或对象中。可以说我们有几个:

[("Billy", "Bob", "Joe", 42), ("Robert", "", "Smith", 31)]

元组和列表的不变性和可变性不是主要区别。列表是相同种类的项目的列表:文件,名称,对象。元组是一组不同类型的对象。它们有不同的用途,许多Python编码器滥用了元组的含义列表。

请不要。


编辑:

我认为这篇博客文章解释了为什么我觉得比我做得更好:http : //news.e-scribe.com/397

None of the answers above point out the real issue of tuples vs lists, which many new to Python seem to not fully understand.

Tuples and lists serve different purposes. Lists store homogenous data. You can and should have a list like this:

["Bob", "Joe", "John", "Sam"]

The reason that is a correct use of lists is because those are all homogenous types of data, specifically, people’s names. But take a list like this:

["Billy", "Bob", "Joe", 42]

That list is one person’s full name, and their age. That isn’t one type of data. The correct way to store that information is either in a tuple, or in an object. Lets say we have a few :

[("Billy", "Bob", "Joe", 42), ("Robert", "", "Smith", 31)]

The immutability and mutability of Tuples and Lists is not the main difference. A list is a list of the same kind of items: files, names, objects. Tuples are a grouping of different types of objects. They have different uses, and many Python coders abuse lists for what tuples are meant for.

Please don’t.


Edit:

I think this blog post explains why I think this better than I did: http://news.e-scribe.com/397


回答 2

如果必须将元组转换为集合或列表才能对其进行排序,那么首先使用元组有什么意义?

在这种情况下,可能没有意义。这不是问题,因为这不是您考虑使用元组的情况之一。

如您所指出的,元组是不可变的。具有不可变类型的原因适用于元组:

  • 复制效率:您可以为它添加别名(将变量绑定到引用),而不是复制不可变的对象
  • 比较效率:使用按引用复制时,可以通过比较位置而不是内容来比较两个变量
  • 实习:您最多需要存储任何不变值的一份副本
  • 无需在并发代码中同步对不可变对象的访问
  • const正确性:不允许更改某些值。(对我而言)这是不可变类型的主要原因。

请注意,特定的Python实现可能无法利用上述所有功能。

字典键必须是不可变的,否则更改键对象的属性可能会使基础数据结构的不变性失效。因此,元组可以潜在地用作键。这是const正确性的结果。

另请参见Dive Into Python中的介绍元组 ” 。

if I must convert a tuple to a set or list to be able to sort them, what’s the point of using a tuple in the first place?

In this particular case, there probably isn’t a point. This is a non-issue, because this isn’t one of the cases where you’d consider using a tuple.

As you point out, tuples are immutable. The reasons for having immutable types apply to tuples:

  • copy efficiency: rather than copying an immutable object, you can alias it (bind a variable to a reference)
  • comparison efficiency: when you’re using copy-by-reference, you can compare two variables by comparing location, rather than content
  • interning: you need to store at most one copy of any immutable value
  • there’s no need to synchronize access to immutable objects in concurrent code
  • const correctness: some values shouldn’t be allowed to change. This (to me) is the main reason for immutable types.

Note that a particular Python implementation may not make use of all of the above features.

Dictionary keys must be immutable, otherwise changing the properties of a key-object can invalidate invariants of the underlying data structure. Tuples can thus potentially be used as keys. This is a consequence of const correctness.

See also “Introducing tuples“, from Dive Into Python.


回答 3

有时我们喜欢使用对象作为字典键

就其价值而言,最近的元组(2.6+)index()count()方法

Sometimes we like to use objects as dictionary keys

For what it’s worth, tuples recently (2.6+) grew index() and count() methods


回答 4

我总是发现对于同一基本数据结构(数组)有两种完全独立的类型是一个笨拙的设计,但实际上并不是一个真正的问题。(每种语言都有其缺陷,包括Python,但这并不是很重要。)

为什么有人会关心变量是否位于与最初分配时不同的内存位置?Python不可变性的全部工作似乎都过分强调了。

这些是不同的东西。可变性与它在内存中的存储位置无关。这意味着它指向内容无法更改。

Python对象创建后无法更改位置,无论是否可变。(更准确地说,id()的值不能改变,实际上是相同的。)可变对象的内部存储可以改变,但这是一个隐藏的实现细节。

>>> x='hello'
>>> id(x)
1234567
>>> x='good bye'
>>> id(x)
5432167

这不是在修改(“变异”)变量。它正在创建一个具有相同名称的新变量,并丢弃旧变量。与变异操作比较:

>>> a = [1,2,3]
>>> id(a)
3084599212L
>>> a[1] = 5
>>> a
[1, 5, 3]
>>> id(a)
3084599212L

正如其他人指出的那样,这允许将数组用作字典以及其他需要不变性的数据结构的键。

请注意,字典的键不必完全不变。只有用作密钥的部分才是不变的。对于某些用途,这是一个重要的区别。例如,您可能有一个代表用户的类,该类通过唯一的用户名比较相等性和哈希值。然后,您可以将其他可变数据挂在类上-“用户已登录”,等等。由于这不会影响相等性或哈希,因此可以将其用作字典中的键并且完全有效。这在Python中不是很常见;我只是指出这一点,因为几个人声称密钥必须是“不可变的”,这只是部分正确的。不过,我已经在C ++映射和集合中使用了很多次。

I’ve always found having two completely separate types for the same basic data structure (arrays) to be an awkward design, but not a real problem in practice. (Every language has its warts, Python included, but this isn’t an important one.)

Why does anyone care if a variable lives at a different place in memory than when it was originally allocated? This whole business of immutability in Python seems to be over emphasized.

These are different things. Mutability isn’t related to the place it’s stored in memory; it means the stuff it points to can’t change.

Python objects can’t change location after they’re created, mutable or not. (More accurately, the value of id() can’t change–same thing, in practice.) The internal storage of mutable objects can change, but that’s a hidden implementation detail.

>>> x='hello'
>>> id(x)
1234567
>>> x='good bye'
>>> id(x)
5432167

This isn’t modifying (“mutating”) the variable; it’s creating a new variable with the same name, and discarding the old one. Compare to a mutating operation:

>>> a = [1,2,3]
>>> id(a)
3084599212L
>>> a[1] = 5
>>> a
[1, 5, 3]
>>> id(a)
3084599212L

As others have pointed out, this allows using arrays as keys to dictionaries, and other data structures that need immutability.

Note that keys for dictionaries do not have to be completely immutable. Only the part of it used as a key needs to be immutable; for some uses, this is an important distinction. For example, you could have a class representing a user, which compares equality and a hash by the unique username. You could then hang other mutable data on the class–“user is logged in”, etc. Since this doesn’t affect equality or the hash, it’s possible and perfectly valid to use this as a key in a dictionary. This isn’t too commonly needed in Python; I just point it out since several people have claimed that keys need to be “immutable”, which is only partially correct. I’ve used this many times with C++ maps and sets, though.


回答 5

正如小偷在评论中所提供的那样,Guido的观点未被完全接受/赞赏:“列表用于同构数据,元组用于异构数据”。当然,许多反对者将此解释为意味着列表中的所有元素应为同一类型。

我喜欢以不同的方式看待它,与过去的其他人一样:

blue= 0, 0, 255
alist= ["red", "green", blue]

请注意,即使type(alist [1])!= type(alist [2]),我也认为列表是同质的。

如果我可以更改元素的顺序,并且代码中没有问题(除了假设,例如“应该排序”),则应使用列表。如果不行(就像blue上面的元组一样),那么我应该使用一个元组。

As gnibbler offered in a comment, Guido had an opinion that is not fully accepted/appreciated: “lists are for homogeneous data, tuples are for heterogeneous data”. Of course, many of the opposers interpreted this as meaning that all elements of a list should be of the same type.

I like to see it differently, not unlike others also have in the past:

blue= 0, 0, 255
alist= ["red", "green", blue]

Note that I consider alist to be homogeneous, even if type(alist[1]) != type(alist[2]).

If I can change the order of the elements and I won’t have issues in my code (apart from assumptions, e.g. “it should be sorted”), then a list should be used. If not (like in the tuple blue above), then I should use a tuple.


回答 6

它们很重要,因为它们可以保证调用者不会忽略传递给它们的对象。如果您这样做:

a = [1,1,1]
doWork(a)

调用方法无法保证呼叫后a的值。然而,

a = (1,1,1)
doWorK(a)

现在,您作为此代码的调用者或阅读者知道a是相同的。在这种情况下,您始终可以复制列表并通过该列表,但是现在您是在浪费时间,而不是使用更具语义意义的语言构造。

They are important since they guarantee the caller that the object they pass won’t be mutated. If you do this:

a = [1,1,1]
doWork(a)

The caller has no guarantee of the value of a after the call. However,

a = (1,1,1)
doWorK(a)

Now you as the caller or as a reader of this code know that a is the same. You could always for this scenario make a copy of the list and pass that but now you are wasting cycles instead of using a language construct that makes more semantic sense.


回答 7

你可以在这里看到一些讨论

you can see here for some discussion on this


回答 8

您的问题(和后续评论)集中在id()在分配期间是否发生变化。专注于不变对象替换和可变对象修改之间的差异的后续影响,而不是差异本身,也许不是最佳方法。

在继续之前,请确保下面演示的行为符合您对Python的期望。

>>> a1 = [1]
>>> a2 = a1
>>> print a2[0]
1
>>> a1[0] = 2
>>> print a2[0]
2

在这种情况下,即使仅为a1分配了新值,a2的内容也被更改。与以下内容对比:

>>> a1 = (1,)
>>> a2 = a1
>>> print a2[0]
1
>>> a1 = (2,)
>>> print a2[0]
1

在后一种情况下,我们替换了整个列表,而不是更新其内容。对于不可变类型(例如元组),这是唯一允许的行为。

为什么这么重要?假设您有一个字典:

>>> t1 = (1,2)
>>> d1 = { t1 : 'three' }
>>> print d1
{(1,2): 'three'}
>>> t1[0] = 0  ## results in a TypeError, as tuples cannot be modified
>>> t1 = (2,3) ## creates a new tuple, does not modify the old one
>>> print d1   ## as seen here, the dict is still intact
{(1,2): 'three'}

使用元组,可以安全地防止字典的键“从其下方”更改为散列为不同值的项目。这对于有效执行至关重要。

Your question (and follow-up comments) focus on whether the id() changes during an assignment. Focusing on this follow-on effect of the difference between immutable object replacement and mutable object modification rather than the difference itself is perhaps not the best approach.

Before we continue, make sure that the behavior demonstrated below is what you expect from Python.

>>> a1 = [1]
>>> a2 = a1
>>> print a2[0]
1
>>> a1[0] = 2
>>> print a2[0]
2

In this case, the contents of a2 was changed, even though only a1 had a new value assigned. Contrast to the following:

>>> a1 = (1,)
>>> a2 = a1
>>> print a2[0]
1
>>> a1 = (2,)
>>> print a2[0]
1

In this latter case, we replaced the entire list, rather than updating its contents. With immutable types such as tuples, this is the only behavior allowed.

Why does this matter? Let’s say you have a dict:

>>> t1 = (1,2)
>>> d1 = { t1 : 'three' }
>>> print d1
{(1,2): 'three'}
>>> t1[0] = 0  ## results in a TypeError, as tuples cannot be modified
>>> t1 = (2,3) ## creates a new tuple, does not modify the old one
>>> print d1   ## as seen here, the dict is still intact
{(1,2): 'three'}

Using a tuple, the dictionary is safe from having its keys changed “out from under it” to items which hash to a different value. This is critical to allow efficient implementation.


在元组列表中查找元素

问题:在元组列表中查找元素

我有一个清单“ a”

a= [(1,2),(1,4),(3,5),(5,7)]

我需要找到一个特定数字的所有元组。说1

result = [(1,2),(1,4)]

我怎么做?

I have a list ‘a’

a= [(1,2),(1,4),(3,5),(5,7)]

I need to find all the tuples for a particular number. say for 1 it will be

result = [(1,2),(1,4)]

How do I do that?


回答 0

如果只希望第一个数字匹配,则可以这样操作:

[item for item in a if item[0] == 1]

如果您仅搜索其中包含1的元组:

[item for item in a if 1 in item]

If you just want the first number to match you can do it like this:

[item for item in a if item[0] == 1]

If you are just searching for tuples with 1 in them:

[item for item in a if 1 in item]

回答 1

实际上,有一种聪明的方法可以用于任何元组列表,其中每个元组的大小为2:您可以将列表转换成一个字典。

例如,

test = [("hi", 1), ("there", 2)]
test = dict(test)
print test["hi"] # prints 1

There is actually a clever way to do this that is useful for any list of tuples where the size of each tuple is 2: you can convert your list into a single dictionary.

For example,

test = [("hi", 1), ("there", 2)]
test = dict(test)
print test["hi"] # prints 1

回答 2

阅读列表理解

[ (x,y) for x, y in a if x  == 1 ]

还要阅读生成器函数yield语句。

def filter_value( someList, value ):
    for x, y in someList:
        if x == value :
            yield x,y

result= list( filter_value( a, 1 ) )

Read up on List Comprehensions

[ (x,y) for x, y in a if x  == 1 ]

Also read up up generator functions and the yield statement.

def filter_value( someList, value ):
    for x, y in someList:
        if x == value :
            yield x,y

result= list( filter_value( a, 1 ) )

回答 3

[tup for tup in a if tup[0] == 1]
[tup for tup in a if tup[0] == 1]

回答 4

for item in a:
   if 1 in item:
       print item
for item in a:
   if 1 in item:
       print item

回答 5

>>> [i for i in a if 1 in i]

[(1,2),(1,4)]

>>> [i for i in a if 1 in i]

[(1, 2), (1, 4)]


回答 6

filter函数还可以提供一个有趣的解决方案:

result = list(filter(lambda x: x.count(1) > 0, a))

它会在列表中的元组中搜索是否出现1。如果搜索仅限于第一个元素,则可以将解决方案修改为:

result = list(filter(lambda x: x[0] == 1, a))

The filter function can also provide an interesting solution:

result = list(filter(lambda x: x.count(1) > 0, a))

which searches the tuples in the list a for any occurrences of 1. If the search is limited to the first element, the solution can be modified into:

result = list(filter(lambda x: x[0] == 1, a))

回答 7

使用过滤功能:

>>> def get_values(iterables,key_to_find):
返回列表(过滤器(lambda x:x中的key_to_find,可迭代)) >>> a = [(1,2 ,,(1,4),(3,5),(5,7)] >>> get_values(a,1) >>> [(1,2),(1,4)]

Using filter function:

>>> def get_values(iterables, key_to_find):
return list(filter(lambda x:key_to_find in x, iterables)) >>> a = [(1,2),(1,4),(3,5),(5,7)] >>> get_values(a, 1) >>> [(1, 2), (1, 4)]

回答 8

takewhile,(此外,还会显示更多值的示例):

>>> a= [(1,2),(1,4),(3,5),(5,7),(0,2)]
>>> import itertools
>>> list(itertools.takewhile(lambda x: x[0]==1,a))
[(1, 2), (1, 4)]
>>> 

如果未排序,例如:

>>> a= [(1,2),(3,5),(1,4),(5,7)]
>>> import itertools
>>> list(itertools.takewhile(lambda x: x[0]==1,sorted(a,key=lambda x: x[0]==1)))
[(1, 2), (1, 4)]
>>> 

Or takewhile, ( addition to this, example of more values is shown ):

>>> a= [(1,2),(1,4),(3,5),(5,7),(0,2)]
>>> import itertools
>>> list(itertools.takewhile(lambda x: x[0]==1,a))
[(1, 2), (1, 4)]
>>> 

if unsorted, like:

>>> a= [(1,2),(3,5),(1,4),(5,7)]
>>> import itertools
>>> list(itertools.takewhile(lambda x: x[0]==1,sorted(a,key=lambda x: x[0]==1)))
[(1, 2), (1, 4)]
>>> 

回答 9

如果要在元组中搜索元组中存在的任何数字,则可以使用

a= [(1,2),(1,4),(3,5),(5,7)]
i=1
result=[]
for j in a:
    if i in j:
        result.append(j)

print(result)

if i==j[0] or i==j[index]如果要搜索特定索引中的数字,也可以使用

if you want to search tuple for any number which is present in tuple then you can use

a= [(1,2),(1,4),(3,5),(5,7)]
i=1
result=[]
for j in a:
    if i in j:
        result.append(j)

print(result)

You can also use if i==j[0] or i==j[index] if you want to search a number in particular index


元组比Python中的列表更有效吗?

问题:元组比Python中的列表更有效吗?

在元素的实例化和检索方面,元组和列表之间是否存在性能差异?

Is there any performance difference between tuples and lists when it comes to instantiation and retrieval of elements?


回答 0

dis模块反汇编函数的字节码,对于查看元组和列表之间的区别很有用。

在这种情况下,您可以看到访问元素会生成相同的代码,但是分配元组要比分配列表快得多。

>>> def a():
...     x=[1,2,3,4,5]
...     y=x[2]
...
>>> def b():
...     x=(1,2,3,4,5)
...     y=x[2]
...
>>> import dis
>>> dis.dis(a)
  2           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               2 (2)
              6 LOAD_CONST               3 (3)
              9 LOAD_CONST               4 (4)
             12 LOAD_CONST               5 (5)
             15 BUILD_LIST               5
             18 STORE_FAST               0 (x)

  3          21 LOAD_FAST                0 (x)
             24 LOAD_CONST               2 (2)
             27 BINARY_SUBSCR
             28 STORE_FAST               1 (y)
             31 LOAD_CONST               0 (None)
             34 RETURN_VALUE
>>> dis.dis(b)
  2           0 LOAD_CONST               6 ((1, 2, 3, 4, 5))
              3 STORE_FAST               0 (x)

  3           6 LOAD_FAST                0 (x)
              9 LOAD_CONST               2 (2)
             12 BINARY_SUBSCR
             13 STORE_FAST               1 (y)
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE

The dis module disassembles the byte code for a function and is useful to see the difference between tuples and lists.

In this case, you can see that accessing an element generates identical code, but that assigning a tuple is much faster than assigning a list.

>>> def a():
...     x=[1,2,3,4,5]
...     y=x[2]
...
>>> def b():
...     x=(1,2,3,4,5)
...     y=x[2]
...
>>> import dis
>>> dis.dis(a)
  2           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               2 (2)
              6 LOAD_CONST               3 (3)
              9 LOAD_CONST               4 (4)
             12 LOAD_CONST               5 (5)
             15 BUILD_LIST               5
             18 STORE_FAST               0 (x)

  3          21 LOAD_FAST                0 (x)
             24 LOAD_CONST               2 (2)
             27 BINARY_SUBSCR
             28 STORE_FAST               1 (y)
             31 LOAD_CONST               0 (None)
             34 RETURN_VALUE
>>> dis.dis(b)
  2           0 LOAD_CONST               6 ((1, 2, 3, 4, 5))
              3 STORE_FAST               0 (x)

  3           6 LOAD_FAST                0 (x)
              9 LOAD_CONST               2 (2)
             12 BINARY_SUBSCR
             13 STORE_FAST               1 (y)
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE

回答 1

通常,您可能期望元组会稍微快一些。但是,您绝对应该测试您的特定情况(如果差异可能会影响程序的性能,请记住“过早的优化是万恶之源”)。

Python非常简单:timeit是您的朋友。

$ python -m timeit "x=(1,2,3,4,5,6,7,8)"
10000000 loops, best of 3: 0.0388 usec per loop

$ python -m timeit "x=[1,2,3,4,5,6,7,8]"
1000000 loops, best of 3: 0.363 usec per loop

和…

$ python -m timeit -s "x=(1,2,3,4,5,6,7,8)" "y=x[3]"
10000000 loops, best of 3: 0.0938 usec per loop

$ python -m timeit -s "x=[1,2,3,4,5,6,7,8]" "y=x[3]"
10000000 loops, best of 3: 0.0649 usec per loop

因此,在这种情况下,元组的实例化速度几乎快一个数量级,但列表的项目访问实际上要快一些!因此,如果您要创建一些元组并多次访问它们,那么实际上使用列表可能会更快。

当然,如果您要更改一项,则列表肯定会更快,因为您需要创建一个完整的新元组来更改一项(因为元组是不可变的)。

In general, you might expect tuples to be slightly faster. However you should definitely test your specific case (if the difference might impact the performance of your program — remember “premature optimization is the root of all evil”).

Python makes this very easy: timeit is your friend.

$ python -m timeit "x=(1,2,3,4,5,6,7,8)"
10000000 loops, best of 3: 0.0388 usec per loop

$ python -m timeit "x=[1,2,3,4,5,6,7,8]"
1000000 loops, best of 3: 0.363 usec per loop

and…

$ python -m timeit -s "x=(1,2,3,4,5,6,7,8)" "y=x[3]"
10000000 loops, best of 3: 0.0938 usec per loop

$ python -m timeit -s "x=[1,2,3,4,5,6,7,8]" "y=x[3]"
10000000 loops, best of 3: 0.0649 usec per loop

So in this case, instantiation is almost an order of magnitude faster for the tuple, but item access is actually somewhat faster for the list! So if you’re creating a few tuples and accessing them many many times, it may actually be faster to use lists instead.

Of course if you want to change an item, the list will definitely be faster since you’d need to create an entire new tuple to change one item of it (since tuples are immutable).


回答 2

摘要

元组的性能往往比几乎每个类别中的列表都要好:

1)元组可以恒定折叠

2)元组可以重复使用而不是复制。

3)元组是紧凑的,并且不会过度分配。

4)元组直接引用其元素。

元组可以恒定折叠

常量元组可以通过Python的窥孔优化器或AST优化器预先计算。另一方面,列表是从头开始构建的:

    >>> from dis import dis

    >>> dis(compile("(10, 'abc')", '', 'eval'))
      1           0 LOAD_CONST               2 ((10, 'abc'))
                  3 RETURN_VALUE   

    >>> dis(compile("[10, 'abc']", '', 'eval'))
      1           0 LOAD_CONST               0 (10)
                  3 LOAD_CONST               1 ('abc')
                  6 BUILD_LIST               2
                  9 RETURN_VALUE 

元组不需要复制

运行tuple(some_tuple)立即返回本身。由于元组是不可变的,因此不必复制它们:

>>> a = (10, 20, 30)
>>> b = tuple(a)
>>> a is b
True

相反,list(some_list)要求将所有数据复制到新列表中:

>>> a = [10, 20, 30]
>>> b = list(a)
>>> a is b
False

元组不会过度分配

由于元组的大小是固定的,因此它可以比需要过度分配以使append()操作高效的列表更紧凑地存储。

这给元组提供了很好的空间优势:

>>> import sys
>>> sys.getsizeof(tuple(iter(range(10))))
128
>>> sys.getsizeof(list(iter(range(10))))
200

这是来自Objects / listobject.c的注释,解释了列表在做什么:

/* This over-allocates proportional to the list size, making room
 * for additional growth.  The over-allocation is mild, but is
 * enough to give linear-time amortized behavior over a long
 * sequence of appends() in the presence of a poorly-performing
 * system realloc().
 * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
 * Note: new_allocated won't overflow because the largest possible value
 *       is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.
 */

元组直接引用其元素

对对象的引用直接合并到元组对象中。相反,列表具有指向外部指针数组的额外间接层。

这使元组在索引查找和拆包方面具有较小的速度优势:

$ python3.6 -m timeit -s 'a = (10, 20, 30)' 'a[1]'
10000000 loops, best of 3: 0.0304 usec per loop
$ python3.6 -m timeit -s 'a = [10, 20, 30]' 'a[1]'
10000000 loops, best of 3: 0.0309 usec per loop

$ python3.6 -m timeit -s 'a = (10, 20, 30)' 'x, y, z = a'
10000000 loops, best of 3: 0.0249 usec per loop
$ python3.6 -m timeit -s 'a = [10, 20, 30]' 'x, y, z = a'
10000000 loops, best of 3: 0.0251 usec per loop

是元组(10, 20)的存储方式:

    typedef struct {
        Py_ssize_t ob_refcnt;
        struct _typeobject *ob_type;
        Py_ssize_t ob_size;
        PyObject *ob_item[2];     /* store a pointer to 10 and a pointer to 20 */
    } PyTupleObject;

这里是列表如何[10, 20]存储:

    PyObject arr[2];              /* store a pointer to 10 and a pointer to 20 */

    typedef struct {
        Py_ssize_t ob_refcnt;
        struct _typeobject *ob_type;
        Py_ssize_t ob_size;
        PyObject **ob_item = arr; /* store a pointer to the two-pointer array */
        Py_ssize_t allocated;
    } PyListObject;

注意,元组对象直接合并了两个数据指针,而列表对象又具有一个间接层,该层指向包含两个数据指针的外部数组。

Summary

Tuples tend to perform better than lists in almost every category:

1) Tuples can be constant folded.

2) Tuples can be reused instead of copied.

3) Tuples are compact and don’t over-allocate.

4) Tuples directly reference their elements.

Tuples can be constant folded

Tuples of constants can be precomputed by Python’s peephole optimizer or AST-optimizer. Lists, on the other hand, get built-up from scratch:

    >>> from dis import dis

    >>> dis(compile("(10, 'abc')", '', 'eval'))
      1           0 LOAD_CONST               2 ((10, 'abc'))
                  3 RETURN_VALUE   

    >>> dis(compile("[10, 'abc']", '', 'eval'))
      1           0 LOAD_CONST               0 (10)
                  3 LOAD_CONST               1 ('abc')
                  6 BUILD_LIST               2
                  9 RETURN_VALUE 

Tuples do not need to be copied

Running tuple(some_tuple) returns immediately itself. Since tuples are immutable, they do not have to be copied:

>>> a = (10, 20, 30)
>>> b = tuple(a)
>>> a is b
True

In contrast, list(some_list) requires all the data to be copied to a new list:

>>> a = [10, 20, 30]
>>> b = list(a)
>>> a is b
False

Tuples do not over-allocate

Since a tuple’s size is fixed, it can be stored more compactly than lists which need to over-allocate to make append() operations efficient.

This gives tuples a nice space advantage:

>>> import sys
>>> sys.getsizeof(tuple(iter(range(10))))
128
>>> sys.getsizeof(list(iter(range(10))))
200

Here is the comment from Objects/listobject.c that explains what lists are doing:

/* This over-allocates proportional to the list size, making room
 * for additional growth.  The over-allocation is mild, but is
 * enough to give linear-time amortized behavior over a long
 * sequence of appends() in the presence of a poorly-performing
 * system realloc().
 * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
 * Note: new_allocated won't overflow because the largest possible value
 *       is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.
 */

Tuples refer directly to their elements

References to objects are incorporated directly in a tuple object. In contrast, lists have an extra layer of indirection to an external array of pointers.

This gives tuples a small speed advantage for indexed lookups and unpacking:

$ python3.6 -m timeit -s 'a = (10, 20, 30)' 'a[1]'
10000000 loops, best of 3: 0.0304 usec per loop
$ python3.6 -m timeit -s 'a = [10, 20, 30]' 'a[1]'
10000000 loops, best of 3: 0.0309 usec per loop

$ python3.6 -m timeit -s 'a = (10, 20, 30)' 'x, y, z = a'
10000000 loops, best of 3: 0.0249 usec per loop
$ python3.6 -m timeit -s 'a = [10, 20, 30]' 'x, y, z = a'
10000000 loops, best of 3: 0.0251 usec per loop

Here is how the tuple (10, 20) is stored:

    typedef struct {
        Py_ssize_t ob_refcnt;
        struct _typeobject *ob_type;
        Py_ssize_t ob_size;
        PyObject *ob_item[2];     /* store a pointer to 10 and a pointer to 20 */
    } PyTupleObject;

Here is how the list [10, 20] is stored:

    PyObject arr[2];              /* store a pointer to 10 and a pointer to 20 */

    typedef struct {
        Py_ssize_t ob_refcnt;
        struct _typeobject *ob_type;
        Py_ssize_t ob_size;
        PyObject **ob_item = arr; /* store a pointer to the two-pointer array */
        Py_ssize_t allocated;
    } PyListObject;

Note that the tuple object incorporates the two data pointers directly while the list object has an additional layer of indirection to an external array holding the two data pointers.


回答 3

元组是不变的,它们的存储效率更高;为了提高效率,列表列出了整体内存,以允许没有常量reallocs的追加。因此,如果您想遍历代码中恒定的值序列(例如for direction in 'up', 'right', 'down', 'left':),则首选元组,因为此类元组是在编译时预先计算的。

访问速度应该相同(它们都作为连续数组存储在内存中)。

但是,当您处理可变数据时,它alist.append(item)是首选atuple+= (item,)。请记住,元组应被视为没有字段名称的记录。

Tuples, being immutable, are more memory efficient; lists, for speed efficiency, overallocate memory in order to allow appends without constant reallocs. So, if you want to iterate through a constant sequence of values in your code (eg for direction in 'up', 'right', 'down', 'left':), tuples are preferred, since such tuples are pre-calculated in compile time.

Read-access speeds should be the same (they are both stored as contiguous arrays in the memory).

But, alist.append(item) is much preferred to atuple+= (item,) when you deal with mutable data. Remember, tuples are intended to be treated as records without field names.


回答 4

array如果列表或元组中的所有项目都属于同一C类型,则还应该考虑标准库中的模块。它将占用更少的内存,并且速度更快。

You should also consider the array module in the standard library if all the items in your list or tuple are of the same C type. It will take less memory and can be faster.


回答 5

仅出于此目的,这是另一个小基准。

In [11]: %timeit list(range(100))
749 ns ± 2.41 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [12]: %timeit tuple(range(100))
781 ns ± 3.34 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [1]: %timeit list(range(1_000))
13.5 µs ± 466 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [2]: %timeit tuple(range(1_000))
12.4 µs ± 182 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [7]: %timeit list(range(10_000))
182 µs ± 810 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [8]: %timeit tuple(range(10_000))
188 µs ± 2.38 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [3]: %timeit list(range(1_00_000))
2.76 ms ± 30.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [4]: %timeit tuple(range(1_00_000))
2.74 ms ± 31.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [10]: %timeit list(range(10_00_000))
28.1 ms ± 266 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [9]: %timeit tuple(range(10_00_000))
28.5 ms ± 447 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

让我们对这些进行平均:

In [3]: l = np.array([749 * 10 ** -9, 13.5 * 10 ** -6, 182 * 10 ** -6, 2.76 * 10 ** -3, 28.1 * 10 ** -3])

In [2]: t = np.array([781 * 10 ** -9, 12.4 * 10 ** -6, 188 * 10 ** -6, 2.74 * 10 ** -3, 28.5 * 10 ** -3])

In [11]: np.average(l)
Out[11]: 0.0062112498000000006

In [12]: np.average(t)
Out[12]: 0.0062882362

In [17]: np.average(t) / np.average(l)  * 100
Out[17]: 101.23946713590554

您可以说它几乎没有定论。

但是可以肯定的是,与列表相比,元组花费101.239%了时间,或者花费了1.239%更多时间来完成这项工作。

Here is another little benchmark, just for the sake of it..

In [11]: %timeit list(range(100))
749 ns ± 2.41 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [12]: %timeit tuple(range(100))
781 ns ± 3.34 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [1]: %timeit list(range(1_000))
13.5 µs ± 466 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [2]: %timeit tuple(range(1_000))
12.4 µs ± 182 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [7]: %timeit list(range(10_000))
182 µs ± 810 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [8]: %timeit tuple(range(10_000))
188 µs ± 2.38 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [3]: %timeit list(range(1_00_000))
2.76 ms ± 30.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [4]: %timeit tuple(range(1_00_000))
2.74 ms ± 31.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [10]: %timeit list(range(10_00_000))
28.1 ms ± 266 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [9]: %timeit tuple(range(10_00_000))
28.5 ms ± 447 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Let’s average these out:

In [3]: l = np.array([749 * 10 ** -9, 13.5 * 10 ** -6, 182 * 10 ** -6, 2.76 * 10 ** -3, 28.1 * 10 ** -3])

In [2]: t = np.array([781 * 10 ** -9, 12.4 * 10 ** -6, 188 * 10 ** -6, 2.74 * 10 ** -3, 28.5 * 10 ** -3])

In [11]: np.average(l)
Out[11]: 0.0062112498000000006

In [12]: np.average(t)
Out[12]: 0.0062882362

In [17]: np.average(t) / np.average(l)  * 100
Out[17]: 101.23946713590554

You can call it almost inconclusive.

But sure, tuples took 101.239% the time, or 1.239% extra time to do the job compared to lists.


回答 6

元组应该比列表稍有效率,因此它比列表更快,因为它们是不可变的。

Tuples should be slightly more efficient and because of that, faster, than lists because they are immutable.


回答 7

Tuple高效阅读的主要原因是因为它是不可变的。

为什么不可变的对象易于阅读?

原因是元组可以存储在内存缓存中,与列表不同。该程序总是可变的(可以随时更改),因此总是从列表存储位置读取。

The main reason for Tuple to be very efficient in reading is because it’s immutable.

Why immutable objects are easy to read?

The reason is tuples can be stored in the memory cache, unlike lists. The program always read from the lists memory location as it is mutable (can change any time).


将元组转换为列表并返回

问题:将元组转换为列表并返回

我目前正在使用平铺地图为pygame中的游戏开发地图编辑器。该级别由以下结构的块构成(尽管更大):

level1 = (
         (1,1,1,1,1,1)
         (1,0,0,0,0,1)
         (1,0,0,0,0,1)
         (1,0,0,0,0,1)
         (1,0,0,0,0,1)
         (1,1,1,1,1,1))

其中“ 1”是一堵墙,而“ 0”是一堵空楼。

以下代码基本上是处理块类型更改的代码:

clicked = pygame.mouse.get_pressed()
if clicked[0] == 1:
    currLevel[((mousey+cameraY)/60)][((mousex+cameraX)/60)] = 1

但是由于级别存储在元组中,因此我无法更改不同块的值。如何轻松更改级别中的不同值?

I’m currently working on a map editor for a game in pygame, using tile maps. The level is built up out of blocks in the following structure (though much larger):

level1 = (
         (1,1,1,1,1,1)
         (1,0,0,0,0,1)
         (1,0,0,0,0,1)
         (1,0,0,0,0,1)
         (1,0,0,0,0,1)
         (1,1,1,1,1,1))

where “1” is a block that’s a wall and “0” is a block that’s empty air.

The following code is basically the one handling the change of block type:

clicked = pygame.mouse.get_pressed()
if clicked[0] == 1:
    currLevel[((mousey+cameraY)/60)][((mousex+cameraX)/60)] = 1

But since the level is stored in a tuple, I’m unable to change the values of the different blocks. How do I go about changing the different values in the level in an easy manner?


回答 0

将元组转换为列表:

>>> t = ('my', 'name', 'is', 'mr', 'tuple')
>>> t
('my', 'name', 'is', 'mr', 'tuple')
>>> list(t)
['my', 'name', 'is', 'mr', 'tuple']

将列表转换为元组:

>>> l = ['my', 'name', 'is', 'mr', 'list']
>>> l
['my', 'name', 'is', 'mr', 'list']
>>> tuple(l)
('my', 'name', 'is', 'mr', 'list')

Convert tuple to list:

>>> t = ('my', 'name', 'is', 'mr', 'tuple')
>>> t
('my', 'name', 'is', 'mr', 'tuple')
>>> list(t)
['my', 'name', 'is', 'mr', 'tuple']

Convert list to tuple:

>>> l = ['my', 'name', 'is', 'mr', 'list']
>>> l
['my', 'name', 'is', 'mr', 'list']
>>> tuple(l)
('my', 'name', 'is', 'mr', 'list')

回答 1

你有一个元组。
要将每个元组转换为列表:

[list(i) for i in level] # list of lists

– – 要么 – –

map(list, level)

完成编辑后,只需将它们转换回即可:

tuple(tuple(i) for i in edited) # tuple of tuples

—或—(感谢@jamylak)

tuple(itertools.imap(tuple, edited))

您还可以使用numpy数组:

>>> a = numpy.array(level1)
>>> a
array([[1, 1, 1, 1, 1, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 1, 1, 1, 1, 1]])

操作:

if clicked[0] == 1:
    x = (mousey + cameraY) // 60 # For readability
    y = (mousex + cameraX) // 60 # For readability
    a[x][y] = 1

You have a tuple of tuples.
To convert every tuple to a list:

[list(i) for i in level] # list of lists

— OR —

map(list, level)

And after you are done editing, just convert them back:

tuple(tuple(i) for i in edited) # tuple of tuples

— OR — (Thanks @jamylak)

tuple(itertools.imap(tuple, edited))

You can also use a numpy array:

>>> a = numpy.array(level1)
>>> a
array([[1, 1, 1, 1, 1, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 0, 0, 0, 0, 1],
       [1, 1, 1, 1, 1, 1]])

For manipulating:

if clicked[0] == 1:
    x = (mousey + cameraY) // 60 # For readability
    y = (mousex + cameraX) // 60 # For readability
    a[x][y] = 1

回答 2

您可以有一个列表列表。使用以下命令将您的元组元组转换为列表列表:

level1 = [list(row) for row in level1]

要么

level1 = map(list, level1)

并进行相应的修改。

但是一个numpy的数组更酷。

You can have a list of lists. Convert your tuple of tuples to a list of lists using:

level1 = [list(row) for row in level1]

or

level1 = map(list, level1)

and modify them accordingly.

But a numpy array is cooler.


回答 3

将元组转换为列表

(给定问题中的元组之间缺少逗号,已添加它以防止出现错误消息)

方法1:

level1 = (
     (1,1,1,1,1,1),
     (1,0,0,0,0,1),
     (1,0,0,0,0,1),
     (1,0,0,0,0,1),
     (1,0,0,0,0,1),
     (1,1,1,1,1,1))

level1 = [list(row) for row in level1]

print(level1)

方法2:

level1 = map(list,level1)

print(list(level1))

方法1–0.0019991397857666016秒-

方法2–0.0010001659393310547秒-

To convert tuples to list

(Commas were missing between the tuples in the given question, it was added to prevent error message)

Method 1:

level1 = (
     (1,1,1,1,1,1),
     (1,0,0,0,0,1),
     (1,0,0,0,0,1),
     (1,0,0,0,0,1),
     (1,0,0,0,0,1),
     (1,1,1,1,1,1))

level1 = [list(row) for row in level1]

print(level1)

Method 2:

level1 = map(list,level1)

print(list(level1))

Method 1 took — 0.0019991397857666016 seconds —

Method 2 took — 0.0010001659393310547 seconds —


回答 4

为什么不尝试将其类型从元组转换为列表,反之亦然。

level1 = (
     (1,1,1,1,1,1)
     (1,0,0,0,0,1)
     (1,0,0,0,0,1)
     (1,0,0,0,0,1)
     (1,0,0,0,0,1)
     (1,1,1,1,1,1))

print(level1)

level1 = list(level1)

print(level1)

level1 = tuple(level1)

print(level1)

Why don’t you try converting its type from a tuple to a list and vice versa.

level1 = (
     (1,1,1,1,1,1)
     (1,0,0,0,0,1)
     (1,0,0,0,0,1)
     (1,0,0,0,0,1)
     (1,0,0,0,0,1)
     (1,1,1,1,1,1))

print(level1)

level1 = list(level1)

print(level1)

level1 = tuple(level1)

print(level1)

回答 5

两种答案都不错,但有一点建议:

元组是不可变的,这意味着它们不能更改。因此,如果需要处理数据,最好将数据存储在列表中,这样可以减少不必要的开销。

在您的情况下,将数据提取到一个列表中,如eumiro所示,并在修改后创建一个类似于Schoolboy给出的结构的类似元组。

另外如建议使用numpy数组是一个更好的选择

Both the answers are good, but a little advice:

Tuples are immutable, which implies that they cannot be changed. So if you need to manipulate data, it is better to store data in a list, it will reduce unnecessary overhead.

In your case extract the data to a list, as shown by eumiro, and after modifying create a similar tuple of similar structure as answer given by Schoolboy.

Also as suggested using numpy array is a better option


回答 6

列出到元组并返回可以如下

import ast, sys
input_str = sys.stdin.read()
input_tuple = ast.literal_eval(input_str)

l = list(input_tuple)
l.append('Python')
#print(l)
tuple_2 = tuple(l)

# Make sure to name the final tuple 'tuple_2'
print(tuple_2)

List to Tuple and back can be done as below

import ast, sys
input_str = sys.stdin.read()
input_tuple = ast.literal_eval(input_str)

l = list(input_tuple)
l.append('Python')
#print(l)
tuple_2 = tuple(l)

# Make sure to name the final tuple 'tuple_2'
print(tuple_2)

回答 7

如果仅使用一个列表而不是一个列表,则可以大大加快工作速度。当然,只有在您所有内部列表的大小都相同的情况下才有可能(这在您的示例中是正确的,因此我假设是这样)。

WIDTH = 6
level1 = [ 1,1,1,1,1,1,
           1,0,0,0,0,1,
           1,0,0,0,0,1,
           1,0,0,0,0,1,
           1,0,0,0,0,1,
           1,1,1,1,1,1 ]
print level1[x + y*WIDTH]  # print value at (x,y)

如果使用位域而不是列表,则可能会更快:

WIDTH = 8  # better align your width to bytes, eases things later
level1 = 0xFC84848484FC  # bit field representation of the level
print "1" if level1 & mask(x, y) else "0"  # print bit at (x, y)
level1 |= mask(x, y)  # set bit at (x, y)
level1 &= ~mask(x, y)  # clear bit at (x, y)

def mask(x, y):
  return 1 << (WIDTH-x + y*WIDTH)

但这仅在您的字段仅包含0或1的情况下有效。如果需要更多值,则必须合并几个位,这会使问题变得更加复杂。

You could dramatically speed up your stuff if you used just one list instead of a list of lists. This is possible of course only if all your inner lists are of the same size (which is true in your example, so I just assume this).

WIDTH = 6
level1 = [ 1,1,1,1,1,1,
           1,0,0,0,0,1,
           1,0,0,0,0,1,
           1,0,0,0,0,1,
           1,0,0,0,0,1,
           1,1,1,1,1,1 ]
print level1[x + y*WIDTH]  # print value at (x,y)

And you could be even faster if you used a bitfield instead of a list:

WIDTH = 8  # better align your width to bytes, eases things later
level1 = 0xFC84848484FC  # bit field representation of the level
print "1" if level1 & mask(x, y) else "0"  # print bit at (x, y)
level1 |= mask(x, y)  # set bit at (x, y)
level1 &= ~mask(x, y)  # clear bit at (x, y)

with

def mask(x, y):
  return 1 << (WIDTH-x + y*WIDTH)

But that’s working only if your fields just contain 0 or 1 of course. If you need more values, you’d have to combine several bits which would make the issue much more complicated.


元组为什么可以包含可变项?

问题:元组为什么可以包含可变项?

如果一个元组是不可变的,那么为什么它可以包含可变项呢?

这似乎是一个矛盾,当可变项(如列表)确实被修改时,它所属的元组保持不变。

If a tuple is immutable then why can it contain mutable items?

It is seemingly a contradiction that when a mutable item such as a list does get modified, the tuple it belongs to maintains being immutable.


回答 0

这是一个很好的问题。

关键的见解是,元组无法知道其中的对象是否可变。使对象可变的唯一方法是拥有更改其数据的方法。通常,无法检测到此情况。

另一个见解是Python的容器实际上不包含任何东西。相反,它们保留对其他对象的引用。同样,Python的变量与编译语言中的变量不同。相反,变量名只是命名空间字典中的键,它们与对应的对象相关联。Ned Batchhelder在他的博客文章中很好地解释了这一点。无论哪种方式,对象仅知道其引用计数。他们不知道这些引用是什么(变量,容器或Python内部函数)。

这两种见解共同解释了您的奥秘(为什么当基础列表更改时,“包含”列表的不可变元组似乎也会更改)。实际上,元组没有改变(它对其他对象的引用与以前相同)。元组无法更改(因为它没有变异方法)。当列表更改时,没有通知元组更改(该列表不知道它是由变量,元组还是其他列表引用)。

当我们讨论该主题时,还有一些其他想法可以帮助您完善关于什么是元组,它们如何工作以及其预期用途的思维模型:

  1. 元组的特征较少在于其不变性,而其特征在于其预期目的。
    元组是Python在一个屋檐下收集异构信息的一种方式。例如, s = ('www.python.org', 80) 将字符串和数字组合在一起,以便主机/端口对可以作为套接字(复合对象)传递。从这个角度来看,具有可变的组件是完全合理的。

  2. 不变性与另一个属性(哈希性)密切相关。但是哈希性不是绝对的属性。如果元组的组成部分之一不可散列,则整个元组也不可散列。例如,t = ('red', [10, 20, 30])不可散列。

最后一个示例显示了一个包含字符串和列表的2元组。元组本身是不可变的(即,它没有任何更改其内容的方法)。同样,字符串是不可变的,因为字符串没有任何突变方法。列表对象确实具有变异方法,因此可以对其进行更改。这表明可变性是对象类型的属性-有些对象具有突变方法,有些则没有。这并不会因为对象被嵌套而改变。

记住两件事。首先,不变性不是魔术,而是缺少突变方法。其次,对象不知道哪些变量或容器引用了它们-它们仅知道引用计数。

希望这对您有用:-)

That’s an excellent question.

The key insight is that tuples have no way of knowing whether the objects inside them are mutable. The only thing that makes an object mutable is to have a method that alters its data. In general, there is no way to detect this.

Another insight is that Python’s containers don’t actually contain anything. Instead, they keep references to other objects. Likewise, Python’s variables aren’t like variables in compiled languages; instead the variable names are just keys in a namespace dictionary where they are associated with a corresponding object. Ned Batchhelder explains this nicely in his blog post. Either way, objects only know their reference count; they don’t know what those references are (variables, containers, or the Python internals).

Together, these two insights explain your mystery (why an immutable tuple “containing” a list seems to change when the underlying list changes). In fact, the tuple did not change (it still has the same references to other objects that it did before). The tuple could not change (because it did not have mutating methods). When the list changed, the tuple didn’t get notified of the change (the list doesn’t know whether it is referred to by a variable, a tuple, or another list).

While we’re on the topic, here are a few other thoughts to help complete your mental model of what tuples are, how they work, and their intended use:

  1. Tuples are characterized less by their immutability and more by their intended purpose.
    Tuples are Python’s way of collecting heterogeneous pieces of information under one roof. For example, s = ('www.python.org', 80) brings together a string and a number so that the host/port pair can be passed around as a socket, a composite object. Viewed in that light, it is perfectly reasonable to have mutable components.

  2. Immutability goes hand-in-hand with another property, hashability. But hashability isn’t an absolute property. If one of the tuple’s components isn’t hashable, then the overall tuple isn’t hashable either. For example, t = ('red', [10, 20, 30]) isn’t hashable.

The last example shows a 2-tuple that contains a string and a list. The tuple itself isn’t mutable (i.e. it doesn’t have any methods that for changing its contents). Likewise, the string is immutable because strings don’t have any mutating methods. The list object does have mutating methods, so it can be changed. This shows that mutability is a property of an object type — some objects have mutating methods and some don’t. This doesn’t change just because the objects are nested.

Remember two things. First, immutability is not magic — it is merely the absence of mutating methods. Second, objects don’t know what variables or containers refer to them — they only know the reference count.

Hope, this was useful to you :-)


回答 1

这是因为元组包含列表,字符串或数字。它们包含对其他对象的引用1无法更改元组包含的引用的顺序并不意味着您不能对与这些引用关联的对象进行突变。2

1.对象,值和类型(请参阅:倒数第二段)
2 .标准类型层次结构(请参阅:“不可变序列”)

That’s because tuples don’t contain lists, strings or numbers. They contain references to other objects.1 The inability to change the sequence of references a tuple contains doesn’t mean that you can’t mutate the objects associated with those references.2

1. Objects, values and types (see: second to last paragraph)
2. The standard type hierarchy (see: “Immutable sequences”)


回答 2

首先,“不变”一词对不同的人可能意味着许多不同的事物。我特别喜欢Eric Lippert在他的博客文章中对不变性的分类。在那里,他列出了这些不变性:

  • 真实性不变
  • 一次写入不变性
  • 冰棒不可变性
  • 浅与深不变性
  • 不变的外墙
  • 观察不变性

可以通过多种方式将它们组合起来,以实现更多种不变性,而且我敢肯定,还有更多种不变性。您似乎对深层(也称为传递)不变性感兴趣的一种不可变性,其中不可变对象只能包含其他不可变对象。

关键在于,深度不变性只是许多不变性中的一种。只要知道您的“不可变”概念可能与其他人的“不可变”概念不同,就可以采用您喜欢的任何一种。

First of all, the word “immutable” can mean many different things to different people. I particularly like how Eric Lippert categorized immutability in his blog post. There, he lists these kinds of immutability:

  • Realio-trulio immutability
  • Write-once immutability
  • Popsicle immutability
  • Shallow vs deep immutability
  • Immutable facades
  • Observational immutability

These can be combined in various ways to make even more kinds of immutability, and I’m sure more exist. The kind of immutability you seems interested in deep (also known as transitive) immutability, in which immutable objects can only contain other immutable objects.

The key point of this is that deep immutability is only one of many, many kinds of immutability. You can adopt whichever kind you prefer, as long as you are aware that your notion of “immutable” probably differs from someone else’s notion of “immutable”.


回答 3

据我所知,这个问题需要改写为关于设计决策的问题:Python的设计者为什么选择创建一个可以包含可变对象的不可变序列类型?

要回答这个问题,我们必须考虑的宗旨元组服务:他们作为快速通用序列。考虑到这一点,很明显为什么元组是不​​可变的却可以包含可变对象。以机智:

  1. 元组速度快且内存效率高:元组的创建是比列表更快的,因为它们是不可变的。不变性意味着可以使用常量折叠将元组创建为常量并按此方式加载。这也意味着由于不需要过度分配等原因,它们的创建速度更快,内存使用效率更高。它们比随机访问列表的速度慢一点,但是对于拆包又要更快(至少在我的机器上)。如果元组是可变的,那么它们就不会达到这样的目的。

  2. 元组是通用的:元组需要能够包含任何类型的对象。它们习惯于(快速地)执行可变长度参数列表之类的事情(通过*函数定义中的运算符)。如果元组不能容纳可变对象,那么它们对于这样的事情将毫无用处。Python必须使用列表,这可能会减慢速度,并且肯定会降低内存效率。

因此,您看到,为了实现其目的,元组必须是不可变的,而且还必须能够包含可变对象。如果Python的设计人员想要创建一个不可变的对象,以保证它“包含”的所有对象也是不可变的,那么他们将必须创建第三个序列类型。增益不值得额外的复杂性。

As I understand it, this question needs to be rephrased as a question about design decisions: Why did the designers of Python choose to create an immutable sequence type that can contain mutable objects?

To answer this question, we have to think about the purpose tuples serve: they serve as fast, general-purpose sequences. With that in mind, it becomes quite obvious why tuples are immutable but can contain mutable objects. To wit:

  1. Tuples are fast and memory efficient: Tuples are faster to create than lists because they are immutable. Immutability means that tuples can be created as constants and loaded as such, using constant folding. It also means they’re faster and more memory efficient to create because there’s no need for overallocation, etc. They’re a bit slower than lists for random item access, but faster again for unpacking (at least on my machine). If tuples were mutable, then they wouldn’t be as fast for purposes such as these.

  2. Tuples are general-purpose: Tuples need to be able to contain any kind of object. They’re used to (quickly) do things like variable-length argument lists (via the * operator in function definitions). If tuples couldn’t hold mutable objects, they would be useless for things like this. Python would have to use lists, which would probably slow things down, and would certainly be less memory efficient.

So you see, in order to fulfill their purpose, tuples must be immutable, but also must be able to contain mutable objects. If the designers of Python wanted to create an immutable object that guarantees that all the objects it “contains” are also immutable, they would have to create a third sequence type. The gain is not worth the extra complexity.


回答 4

您不能更改id其项目。因此它将始终包含相同的项目。

$ python
>>> t = (1, [2, 3])
>>> id(t[1])
12371368
>>> t[1].append(4)
>>> id(t[1])
12371368

You cannot change the id of its items. So it will always contain the same items.

$ python
>>> t = (1, [2, 3])
>>> id(t[1])
12371368
>>> t[1].append(4)
>>> id(t[1])
12371368

回答 5

我将在这里走出去的肢体和说,这里的相关部分是,虽然你可以改变一个列表的内容或对象的状态,包含一个元组中,你不能改变对象或列表在那里。如果您有一个依赖于事物[3]的列表,即使它为空,那么我会发现这很有用。

I’ll go out on a limb here and say that the relevant part here is that while you can change the contents of a list, or the state of an object, contained within a tuple, what you can’t change is that the object or list is there. If you had something that depended on thing[3] being a list, even if empty, then I could see this being useful.


回答 6

原因之一是Python中没有通用的方法将可变类型转换为不可变类型(请参见被拒绝的PEP 351以及有关为什么被拒绝的链接讨论)。因此,如果有此限制,就不可能将各种类型的对象放入元组,包括几乎所有用户创建的不可哈希对象。

字典和集合具有此限制的唯一原因是它们要求对象是可哈希的,因为它们在内部实现为哈希表。但是请注意,具有讽刺意味的是,字典和集合本身并不是不可变的(或不可哈希的)。元组不使用对象的哈希,因此其可变性无关紧要。

One reason is that there is no general way in Python to convert a mutable type into an immutable one (see the rejected PEP 351, and the linked discussion for why it was rejected). Thus, it would be impossible to put various types of objects in tuples if it had this restriction, including just about any user-created non-hashable object.

The only reason that dictionaries and sets have this restriction is that they require the objects to be hashable, since they are internally implemented as hash tables. But note that, ironically, dictionaries and sets themselves are not immutable (or hashable). Tuples do not use an object’s hash, so its mutability does not matter.


回答 7

从元组本身不能扩展或收缩的意义上讲,元组是不可变的,并不是其中包含的所有项都是不可变的。否则,元组变钝。

A tuple is immutable in the sense that the tuple itself can not expand or shrink, not that all the items contained themselves are immutable. Otherwise tuples are dull.


元组比较在Python中如何工作?

问题:元组比较在Python中如何工作?

我一直在阅读Core Python编程书,作者展示了一个类似的示例:

(4, 5) < (3, 5) # Equals false

所以,我想知道为什么/为什么等于假?python如何比较这两个元组?

顺便说一句,这本书没有解释。

I have been reading the Core Python programming book, and the author shows an example like:

(4, 5) < (3, 5) # Equals false

So, I’m wondering, how/why does it equal false? How does python compare these two tuples?

Btw, it’s not explained in the book.


回答 0

比较元组的位置:将第一元组的第一项与第二元组的第一项进行比较;如果它们不相等(即第一个大于或小于第二个),则这是比较的结果,否则将考虑第二个,然后是第三个,依此类推。

请参阅常见序列操作

相同类型的序列也支持比较。特别是,通过比较相应的元素按字典顺序比较了元组和列表。这意味着要比较相等,每个元素必须比较相等,并且两个序列必须具有相同的类型并且具有相同的长度。

还可以进行值比较以获取更多详细信息:

内置集合之间的词法比较如下:

  • 为了使两个集合比较相等,它们必须是同一类型,具有相同的长度,并且每对对应的元素必须比较相等(例如, [1,2] == (1,2)由于类型不同为false)。
  • 支持顺序比较的集合的排序与其第一个不相等元素相同(例如,[1,2,x] <= [1,2,y]具有与相同的值x <= y)。如果不存在相应的元素,则将对较短的集合进行排序(例如,[1,2] < [1,2,3]为true)。

如果不相等,则序列与它们的第一个不同元素的排序相同。例如,cmp([1,2,x],[1,2,y])返回的结果与cmp(x,y)相同。如果不存在相应的元素,则较短的序列被视为较小的序列(例如[1,2] <[1,2,3]返回True)。

注1<>并不意味着与“大于”,“小于”,而是“是之前”和“之后”:所以(0,1)“是之前”(1,0)。

注2:根据元组的长度,元组不能视为n维空间中的向量

注意3:参考问题/programming/36911617/python-2-tuple-comparison:仅当第一个元组的任何元素大于对应的元组时,才认为该元组比另一个元组“更大”一秒。

Tuples are compared position by position: the first item of the first tuple is compared to the first item of the second tuple; if they are not equal (i.e. the first is greater or smaller than the second) then that’s the result of the comparison, else the second item is considered, then the third and so on.

See Common Sequence Operations:

Sequences of the same type also support comparisons. In particular, tuples and lists are compared lexicographically by comparing corresponding elements. This means that to compare equal, every element must compare equal and the two sequences must be of the same type and have the same length.

Also Value Comparisons for further details:

Lexicographical comparison between built-in collections works as follows:

  • For two collections to compare equal, they must be of the same type, have the same length, and each pair of corresponding elements must compare equal (for example, [1,2] == (1,2) is false because the type is not the same).
  • Collections that support order comparison are ordered the same as their first unequal elements (for example, [1,2,x] <= [1,2,y] has the same value as x <= y). If a corresponding element does not exist, the shorter collection is ordered first (for example, [1,2] < [1,2,3] is true).

If not equal, the sequences are ordered the same as their first differing elements. For example, cmp([1,2,x], [1,2,y]) returns the same as cmp(x,y). If the corresponding element does not exist, the shorter sequence is considered smaller (for example, [1,2] < [1,2,3] returns True).

Note 1: < and > do not mean “smaller than” and “greater than” but “is before” and “is after”: so (0, 1) “is before” (1, 0).

Note 2: tuples must not be considered as vectors in a n-dimensional space, compared according to their length.

Note 3: referring to question https://stackoverflow.com/questions/36911617/python-2-tuple-comparison: do not think that a tuple is “greater” than another only if any element of the first is greater than the corresponding one in the second.


回答 1

Python文档做解释。

使用对应元素的比较,按字典顺序比较元组和列表。这意味着要比较相等,每个元素必须比较相等,并且两个序列必须具有相同的类型并且长度相同。

The Python documentation does explain it.

Tuples and lists are compared lexicographically using comparison of corresponding elements. This means that to compare equal, each element must compare equal and the two sequences must be of the same type and have the same length.


回答 2

Python 2.5的文档解释了它做好。

使用对应元素的比较,按字典顺序比较元组和列表。这意味着要比较相等,每个元素必须比较相等,并且两个序列必须具有相同的类型并且具有相同的长度。

如果不相等,则序列与它们的第一个不同元素的排序相同。例如,cmp([1,2,x],[1,2,y])返回的结果与cmp(x,y)相同。如果相应的元素不存在,则较短的序列首先被排序(例如[1,2] <[1,2,3])。

不幸的是,该页面似乎在文档的最新版本中消失了。

The python 2.5 documentation explains it well.

Tuples and lists are compared lexicographically using comparison of corresponding elements. This means that to compare equal, each element must compare equal and the two sequences must be of the same type and have the same length.

If not equal, the sequences are ordered the same as their first differing elements. For example, cmp([1,2,x], [1,2,y]) returns the same as cmp(x,y). If the corresponding element does not exist, the shorter sequence is ordered first (for example, [1,2] < [1,2,3]).

Unfortunately that page seems to have disappeared in the documentation for more recent versions.


回答 3

在进行整数比较之前,我有些困惑,因此我将通过一个示例来说明它对初学者更友好

a = ('A','B','C') # see it as the string "ABC" b = ('A','B','D')

A转换为其对应的ASCII ord('A') #65与其他元素相同的

因此, >> a>b # True 您可以将其视为字符串之间的比较(确实如此)

整数也是如此。

x = (1,2,2) # see it the string "123" y = (1,2,3) x > y # False

因为(1不大于1,移至下一个,2不大于2,移至下一个2小于三-按字典顺序-)

上面的答案中提到了关键点

认为它是一个元素,在另一个字母前不是一个元素大于一个元素,在这种情况下,将所有元组元素视为一个字符串。

I had some confusion before regarding integer comparsion, so I will explain it to be more beginner friendly with an example

a = ('A','B','C') # see it as the string "ABC" b = ('A','B','D')

A is converted to its corresponding ASCII ord('A') #65 same for other elements

So, >> a>b # True you can think of it as comparing between string (It is exactly, actually)

the same thing goes for integers too.

x = (1,2,2) # see it the string "123" y = (1,2,3) x > y # False

because (1 is not greater than 1, move to the next, 2 is not greater than 2, move to the next 2 is less than three -lexicographically -)

The key point is mentioned in the answer above

think of it as an element is before another alphabetically not element is greater than an element and in this case consider all the tuple elements as one string.


将变量添加到元组

问题:将变量添加到元组

我正在学习Python并创建数据库连接。在尝试添加到数据库时,我正在考虑从信息中创建元组,然后将其添加到数据库中。

我正在做什么:我正在从用户那里获取信息并将其存储在变量中。我可以将这些变量添加到元组吗?您能帮我语法吗?

另外,如果有有效的方法,请分享…

编辑 让我稍微编辑一下这个问题…我只需要元组即可将信息输入数据库。将信息添加到数据库后,是否应该删除元组?我的意思是我不再需要元组了。

I am learning Python and creating a database connection. While trying to add to the DB, I am thinking of creating tuples out of information and then add them to the DB.

What I am Doing: I am taking information from the user and store it in variables. Can I add these variables into a tuple? Can you please help me with the syntax?

Also if there is an efficient way of doing this, please share…

EDIT Let me edit this question a bit…I only need the tuple to enter info into the DB. Once the information is added to the DB, should I delete the tuple? I mean I don’t need the tuple anymore.


回答 0

元组是不可变的;您无法在构造后更改它们包含的变量。但是,您可以将它们串联或切片以形成新的元组:

a = (1, 2, 3)
b = a + (4, 5, 6)  # (1, 2, 3, 4, 5, 6)
c = b[1:]  # (2, 3, 4, 5, 6)

并且,当然,要根据现有价值来构建它们:

name = "Joe"
age = 40
location = "New York"
joe = (name, age, location)

Tuples are immutable; you can’t change which variables they contain after construction. However, you can concatenate or slice them to form new tuples:

a = (1, 2, 3)
b = a + (4, 5, 6)  # (1, 2, 3, 4, 5, 6)
c = b[1:]  # (2, 3, 4, 5, 6)

And, of course, build them from existing values:

name = "Joe"
age = 40
location = "New York"
joe = (name, age, location)

回答 1

您可以从类似的空白元组开始t = ()。您可以添加+,但必须添加另一个元组。如果要添加单个元素,请使其成为单例:t = t + (element,)。您可以添加带有或不带有逗号的多个元素的元组。

>>> t = ()
>>> t = t + (1,)
>>> t
(1,)
>>> t = t + (2,)
>>> t
(1, 2)
>>> t = t + (3, 4, 5)
>>> t
(1, 2, 3, 4, 5)
>>> t = t + (6, 7, 8,)
>>> t
(1, 2, 3, 4, 5, 6, 7, 8)

You can start with a blank tuple with something like t = (). You can add with +, but you have to add another tuple. If you want to add a single element, make it a singleton: t = t + (element,). You can add a tuple of multiple elements with or without that trailing comma.

>>> t = ()
>>> t = t + (1,)
>>> t
(1,)
>>> t = t + (2,)
>>> t
(1, 2)
>>> t = t + (3, 4, 5)
>>> t
(1, 2, 3, 4, 5)
>>> t = t + (6, 7, 8,)
>>> t
(1, 2, 3, 4, 5, 6, 7, 8)

回答 2

尚未提及的另一种策略是使用追加到列表,然后在最后将列表转换为元组:

mylist = []
for x in range(5):
    mylist.append(x)
mytuple = tuple(mylist)
print mytuple

退货

(0, 1, 2, 3, 4)

当我必须将元组作为函数参数传递时,有时会使用此函数,这对于numpy函数通常是必需的。

Another tactic not yet mentioned is using appending to a list, and then converting the list to a tuple at the end:

mylist = []
for x in range(5):
    mylist.append(x)
mytuple = tuple(mylist)
print mytuple

returns

(0, 1, 2, 3, 4)

I sometimes use this when I have to pass a tuple as a function argument, which is often necessary for the numpy functions.


回答 3

在Python 3中,您可以用来*根据原始元组以及新元素创建一个新的元组元素。

>>> tuple1 = ("foo", "bar")
>>> tuple2 = (*tuple1, "baz")
>>> tuple2
('foo', 'bar', 'baz')

In Python 3, you can use * to create a new tuple of elements from the original tuple along with the new element.

>>> tuple1 = ("foo", "bar")
>>> tuple2 = (*tuple1, "baz")
>>> tuple2
('foo', 'bar', 'baz')

The byte code is almost the same as tuple1 + ("baz",)

Python 3.7.5 (default, Oct 22 2019, 10:35:10) 
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def f():
...     tuple1 = ("foo", "bar")
...     tuple2 = (*tuple1, "baz")
...     return tuple2
... 
>>> def g():
...     tuple1 = ("foo", "bar")
...     tuple2 = tuple1 + ("baz",)
...     return tuple2
... 
>>> from dis import dis
>>> dis(f)
  2           0 LOAD_CONST               1 (('foo', 'bar'))
              2 STORE_FAST               0 (tuple1)

  3           4 LOAD_FAST                0 (tuple1)
              6 LOAD_CONST               3 (('baz',))
              8 BUILD_TUPLE_UNPACK       2
             10 STORE_FAST               1 (tuple2)

  4          12 LOAD_FAST                1 (tuple2)
             14 RETURN_VALUE
>>> dis(g)
  2           0 LOAD_CONST               1 (('foo', 'bar'))
              2 STORE_FAST               0 (tuple1)

  3           4 LOAD_FAST                0 (tuple1)
              6 LOAD_CONST               2 (('baz',))
              8 BINARY_ADD
             10 STORE_FAST               1 (tuple2)

  4          12 LOAD_FAST                1 (tuple2)
             14 RETURN_VALUE

The only difference is BUILD_TUPLE_UNPACK vs BINARY_ADD. The exact performance depends on the Python interpreter implementation, but it’s easier to implement BUILD_TUPLE_UNPACK fast than BINARY_ADD because BINARY_ADD is a polymorphic operator, requiring additional type calculation and implicit conversion.


回答 4

“一旦信息添加到数据库,我应该删除元组吗?我的意思是我不再需要元组。”

没有。

通常,没有理由删除任何内容。有一些特殊情况需要删除,但是非常罕见。

只需定义一个狭窄的范围(即类中的函数定义或方法函数),对象就会在范围的末尾被垃圾回收。

不用担心删除任何内容。

[注意。我曾与一个人合作,除了试图删除对象外,他还一直在编写“重置”方法来清除它们。就像他要保存它们并重用它们一样。也是一个愚蠢的自负。只需忽略不再使用的对象。如果用足够小的代码块定义函数,就没有什么要考虑的了。]

” once the info is added to the DB, should I delete the tuple? i mean i dont need the tuple anymore.”

No.

Generally, there’s no reason to delete anything. There are some special cases for deleting, but they’re very, very rare.

Simply define a narrow scope (i.e., a function definition or a method function in a class) and the objects will be garbage collected at the end of the scope.

Don’t worry about deleting anything.

[Note. I worked with a guy who — in addition to trying to delete objects — was always writing “reset” methods to clear them out. Like he was going to save them and reuse them. Also a silly conceit. Just ignore the objects you’re no longer using. If you define your functions in small-enough blocks of code, you have nothing more to think about.]


回答 5

如下所示:

info_1 = "one piece of info"
info_2 = "another piece"
vars = (info_1, info_2)
# 'vars' is now a tuple with the values ("info_1", "info_2")

但是,Python中的元组是不可变的,因此一旦创建元组,就不能将变量追加到元组中。

It’s as easy as the following:

info_1 = "one piece of info"
info_2 = "another piece"
vars = (info_1, info_2)
# 'vars' is now a tuple with the values ("info_1", "info_2")

However, tuples in Python are immutable, so you cannot append variables to a tuple once it is created.


回答 6

正如其他答案所指出的那样,您无法更改现有的元组,但始终可以创建一个新的元组(该元组可能会从现有的元组和/或其他来源中获取部分或全部项目)。

例如,如果所有感兴趣的项都在标量变量中,并且您知道这些变量的名称,则:

def maketuple(variables, names):
  return tuple(variables[n] for n in names)

使用,例如,在本示例中:

def example():
  x = 23
  y = 45
  z = 67
  return maketuple(vars(), 'x y z'.split())

当然,这一种情况将更简单地表示为(x, y, z)(或什至完全不使用名称(23, 45, 67)),但是该maketuple方法在一些更复杂的情况下可能很有用(例如,要使用的名称也是动态确定的,并在使用过程中附加到列表中)。计算)。

As other answers have noted, you cannot change an existing tuple, but you can always create a new tuple (which may take some or all items from existing tuples and/or other sources).

For example, if all the items of interest are in scalar variables and you know the names of those variables:

def maketuple(variables, names):
  return tuple(variables[n] for n in names)

to be used, e.g, as in this example:

def example():
  x = 23
  y = 45
  z = 67
  return maketuple(vars(), 'x y z'.split())

of course this one case would be more simply expressed as (x, y, z) (or even foregoing the names altogether, (23, 45, 67)), but the maketuple approach might be useful in some more complicated cases (e.g. where the names to use are also determined dynamically and appended to a list during the computation).


回答 7

我很确定python中的语法是:

user_input1 = raw_input("Enter Name: ")
user_input2 = raw_input("Enter Value: ")
info = (user_input1, user_input2)

一旦设置,元组就不能更改。

I’m pretty sure the syntax for this in python is:

user_input1 = raw_input("Enter Name: ")
user_input2 = raw_input("Enter Value: ")
info = (user_input1, user_input2)

once set, tuples cannot be changed.


忽略python多个返回值

问题:忽略python多个返回值

假设我有一个Python函数,可在一个元组中返回多个值:

def func():
    return 1, 2

有没有一种好的方法可以忽略其中一个结果,而不仅仅是分配给一个临时变量?假设我只对第一个值感兴趣,是否有比这更好的方法:

x, temp = func()

Say I have a Python function that returns multiple values in a tuple:

def func():
    return 1, 2

Is there a nice way to ignore one of the results rather than just assigning to a temporary variable? Say if I was only interested in the first value, is there a better way than this:

x, temp = func()

回答 0

一种常见的约定是对您要忽略的元组的元素使用“ _”作为变量名。例如:

def f():
    return 1, 2, 3

_, _, x = f()

One common convention is to use a “_” as a variable name for the elements of the tuple you wish to ignore. For instance:

def f():
    return 1, 2, 3

_, _, x = f()

回答 1

您可以使用x = func()[0]返回第一个值,x = func()[1]返回第二个值,依此类推。

如果您想一次获取多个值,请使用x, y = func()[2:4]

You can use x = func()[0] to return the first value, x = func()[1] to return the second, and so on.

If you want to get multiple values at a time, use something like x, y = func()[2:4].


回答 2

如果您使用的是Python 3,则可以在变量(在作业的左侧)之前使用星号,以使其成为解压缩列表。

# Example 1: a is 1 and b is [2, 3]

a, *b = [1, 2, 3]

# Example 2: a is 1, b is [2, 3], and c is 4

a, *b, c = [1, 2, 3, 4]

# Example 3: b is [1, 2] and c is 3

*b, c = [1, 2, 3]       

# Example 4: a is 1 and b is []

a, *b = [1]

If you’re using Python 3, you can you use the star before a variable (on the left side of an assignment) to have it be a list in unpacking.

# Example 1: a is 1 and b is [2, 3]

a, *b = [1, 2, 3]

# Example 2: a is 1, b is [2, 3], and c is 4

a, *b, c = [1, 2, 3, 4]

# Example 3: b is [1, 2] and c is 3

*b, c = [1, 2, 3]       

# Example 4: a is 1 and b is []

a, *b = [1]

回答 3

请记住,当您返回多个项目时,您实际上是在返回一个元组。因此,您可以执行以下操作:

def func():
    return 1, 2

print func()[0] # prints 1
print func()[1] # prints 2

Remember, when you return more than one item, you’re really returning a tuple. So you can do things like this:

def func():
    return 1, 2

print func()[0] # prints 1
print func()[1] # prints 2

回答 4

通常的做法是使用哑变量_(单个下划线),正如前面在此处指出的那样。

但是,为了避免与该变量名的其他用法冲突(请参阅响应)__,如ncoghlan所指出的那样,最好使用(双下划线)代替一次性变量。例如:

x, __ = func()

The common practice is to use the dummy variable _ (single underscore), as many have indicated here before.

However, to avoid collisions with other uses of that variable name (see this response) it might be a better practice to use __ (double underscore) instead as a throwaway variable, as pointed by ncoghlan. E.g.:

x, __ = func()

回答 5

三个简单的选择。

明显

x, _ = func()

x, junk = func()

可怕

x = func()[0]

并且有许多方法可以通过装饰器来实现。

def val0( aFunc ):
    def pick0( *args, **kw ):
        return aFunc(*args,**kw)[0]
    return pick0

func0= val0(func)

Three simple choices.

Obvious

x, _ = func()

x, junk = func()

Hideous

x = func()[0]

And there are ways to do this with a decorator.

def val0( aFunc ):
    def pick0( *args, **kw ):
        return aFunc(*args,**kw)[0]
    return pick0

func0= val0(func)

回答 6

最好的解决方案可能是命名事物,而不是返回无意义的元组。除非返回的项目的顺序背后有逻辑。

def func():
    return {'lat': 1, 'lng': 2}

latitude = func()['lat']

如果您想添加有关返回内容的更多信息,甚至可以使用namedtuple(不仅仅是字典,这些是坐标):

from collections import namedtuple 

Coordinates = namedtuple('Coordinates', ['lat', 'lng'])

def func():
    return Coordinates(lat=1, lng=2)

latitude = func().lat

如果字典/元组中的对象紧密地绑在一起,那么甚至最好为其定义一个类。这样,您还可以定义此类型对象之间的交互,并提供有关如何使用它们的API。接下来的自然问题是:什么时候应该在Python中使用类?

The best solution probably is to name things instead of returning meaningless tuples (unless there is some logic behind the order of the returned items). You can for example use a dictionary:

def func():
    return {'lat': 1, 'lng': 2}
    
latitude = func()['lat']

You could even use namedtuple if you want to add extra information about what you are returning (it’s not just a dictionary, it’s a pair of coordinates):

from collections import namedtuple 

Coordinates = namedtuple('Coordinates', ['lat', 'lng'])

def func():
    return Coordinates(lat=1, lng=2)

latitude = func().lat

If the objects within your dictionary/tuple are strongly tied together then it may be a good idea to even define a class for it. That way you’ll also be able to define more complex operations. A natural question that follows is: When should I be using classes in Python?

Most recent versions of python (≥ 3.7) have dataclasses which you can use to define classes with very few lines of code:

from dataclasses import dataclass

@dataclass
class Coordinates:
    lat: float = 0
    lng: float = 0

def func():
    return Coordinates(lat=1, lng=2)

latitude = func().lat

The primary advantage of dataclasses over namedtuple is that its easier to extend, but there are other differences. Note that by default, dataclasses are mutable, but you can use @dataclass(frozen=True) instead of @dataclass to force them being immutable.


回答 7

在我看来,这似乎是最佳选择:

val1, val2, ignored1, ignored2 = some_function()

它不是神秘的或丑陋的(就像func()[index]方法一样),并且清楚地说明了您的目的。

This seems like the best choice to me:

val1, val2, ignored1, ignored2 = some_function()

It’s not cryptic or ugly (like the func()[index] method), and clearly states your purpose.


回答 8

这不是问题的直接答案。而是回答了这个问题:“如何从许多可能的选项中选择特定的函数输出?”。

如果您能够编写该函数(即它不在库中,则无法修改),则添加一个输入自变量,以指示您要从该函数中获取的内容。将其设为具有默认值的命名参数,这样,在“普通情况”下,您甚至不必指定它。

    def fancy_function( arg1, arg2, return_type=1 ):
        ret_val = None
        if( 1 == return_type ):
            ret_val = arg1 + arg2
        elif( 2 == return_type ):
            ret_val = [ arg1, arg2, arg1 * arg2 ]
        else:
            ret_val = ( arg1, arg2, arg1 + arg2, arg1 * arg2 ) 
        return( ret_val )

该方法为所需的输出提供了“高级警告”功能。因此,它可以跳过不需要的处理,仅执行获得所需输出的必要工作。同样因为Python进行动态类型化,所以返回类型可以更改。请注意,示例如何返回标量,列表或元组……随您便!

This is not a direct answer to the question. Rather it answers this question: “How do I choose a specific function output from many possible options?”.

If you are able to write the function (ie, it is not in a library you cannot modify), then add an input argument that indicates what you want out of the function. Make it a named argument with a default value so in the “common case” you don’t even have to specify it.

    def fancy_function( arg1, arg2, return_type=1 ):
        ret_val = None
        if( 1 == return_type ):
            ret_val = arg1 + arg2
        elif( 2 == return_type ):
            ret_val = [ arg1, arg2, arg1 * arg2 ]
        else:
            ret_val = ( arg1, arg2, arg1 + arg2, arg1 * arg2 ) 
        return( ret_val )

This method gives the function “advanced warning” regarding the desired output. Consequently it can skip unneeded processing and only do the work necessary to get your desired output. Also because Python does dynamic typing, the return type can change. Notice how the example returns a scalar, a list or a tuple… whatever you like!


回答 9

如果这是您一直使用的函数,但始终舍弃第二个参数,那么我认为无需使用第二个返回值就可以为该函数创建别名不会太麻烦lambda

def func():
    return 1, 2

func_ = lambda: func()[0] 

func_()  # Prints 1 

If this is a function that you use all the time but always discard the second argument, I would argue that it is less messy to create an alias for the function without the second return value using lambda.

def func():
    return 1, 2

func_ = lambda: func()[0] 

func_()  # Prints 1 

回答 10

当您从一个函数获得许多输出并且不想多次调用它时,我认为选择结果的最简单方法是:

results = fct()
a,b = [results[i] for i in list_of_index]

作为最低限度的工作示例,还演示了该函数仅被调用一次:

def fct(a):
    b=a*2
    c=a+2
    d=a+b
    e=b*2
    f=a*a
    print("fct called")
    return[a,b,c,d,e,f]

results=fct(3)
> fct called

x,y = [results[i] for i in [1,4]]

和值是预期的:

results
> [3,6,5,9,12,9]
x
> 6
y
> 12

为了方便起见,还可以使用Python列表索引:

x,y = [results[i] for i in [0,-2]]

返回:a = 3和b = 12

When you have many output from a function and you don’t want to call it multiple times, I think the clearest way for selecting the results would be :

results = fct()
a,b = [results[i] for i in list_of_index]

As a minimum working example, also demonstrating that the function is called only once :

def fct(a):
    b=a*2
    c=a+2
    d=a+b
    e=b*2
    f=a*a
    print("fct called")
    return[a,b,c,d,e,f]

results=fct(3)
> fct called

x,y = [results[i] for i in [1,4]]

And the values are as expected :

results
> [3,6,5,9,12,9]
x
> 6
y
> 12

For convenience, Python list indexes can also be used :

x,y = [results[i] for i in [0,-2]]

Returns : a = 3 and b = 12


如何将列表合并为元组列表?

问题:如何将列表合并为元组列表?

实现以下目标的Python方法是什么?

# Original lists:

list_a = [1, 2, 3, 4]
list_b = [5, 6, 7, 8]

# List of tuples from 'list_a' and 'list_b':

list_c = [(1,5), (2,6), (3,7), (4,8)]

的每个成员list_c都是一个元组,其第一个成员是from list_a,第二个成员是from list_b

What is the Pythonic approach to achieve the following?

# Original lists:

list_a = [1, 2, 3, 4]
list_b = [5, 6, 7, 8]

# List of tuples from 'list_a' and 'list_b':

list_c = [(1,5), (2,6), (3,7), (4,8)]

Each member of list_c is a tuple, whose first member is from list_a and the second is from list_b.


回答 0

在Python 2中:

>>> list_a = [1, 2, 3, 4]
>>> list_b = [5, 6, 7, 8]
>>> zip(list_a, list_b)
[(1, 5), (2, 6), (3, 7), (4, 8)]

在Python 3中:

>>> list_a = [1, 2, 3, 4]
>>> list_b = [5, 6, 7, 8]
>>> list(zip(list_a, list_b))
[(1, 5), (2, 6), (3, 7), (4, 8)]

In Python 2:

>>> list_a = [1, 2, 3, 4]
>>> list_b = [5, 6, 7, 8]
>>> zip(list_a, list_b)
[(1, 5), (2, 6), (3, 7), (4, 8)]

In Python 3:

>>> list_a = [1, 2, 3, 4]
>>> list_b = [5, 6, 7, 8]
>>> list(zip(list_a, list_b))
[(1, 5), (2, 6), (3, 7), (4, 8)]

回答 1

在python 3.0中,zip返回一个zip对象。您可以调用以获得清单list(zip(a, b))

In python 3.0 zip returns a zip object. You can get a list out of it by calling list(zip(a, b)).


回答 2

您可以使用地图lambda

a = [2,3,4]
b = [5,6,7]
c = map(lambda x,y:(x,y),a,b)

如果原始列表的长度不匹配,这也将起作用

You can use map lambda

a = [2,3,4]
b = [5,6,7]
c = map(lambda x,y:(x,y),a,b)

This will also work if there lengths of original lists do not match


回答 3

您正在寻找内置功能zip

Youre looking for the builtin function zip.


回答 4

我不确定这是否是pythonic方式,但是如果两个列表具有相同数量的元素,这似乎很简单:

list_a = [1, 2, 3, 4]

list_b = [5, 6, 7, 8]

list_c=[(list_a[i],list_b[i]) for i in range(0,len(list_a))]

I am not sure if this a pythonic way or not but this seems simple if both lists have the same number of elements :

list_a = [1, 2, 3, 4]

list_b = [5, 6, 7, 8]

list_c=[(list_a[i],list_b[i]) for i in range(0,len(list_a))]

回答 5

我知道这是一个古老的问题,已经得到回答,但是由于某些原因,我仍然想发布此替代解决方案。我知道很容易找出哪个内置函数可以完成您所需的“魔术”,但是知道您可以自己完成该操作也不会有什么害处。

>>> list_1 = ['Ace', 'King']
>>> list_2 = ['Spades', 'Clubs', 'Diamonds']
>>> deck = []
>>> for i in range(max((len(list_1),len(list_2)))):
        while True:
            try:
                card = (list_1[i],list_2[i])
            except IndexError:
                if len(list_1)>len(list_2):
                    list_2.append('')
                    card = (list_1[i],list_2[i])
                elif len(list_1)<len(list_2):
                    list_1.append('')
                    card = (list_1[i], list_2[i])
                continue
            deck.append(card)
            break
>>>
>>> #and the result should be:
>>> print deck
>>> [('Ace', 'Spades'), ('King', 'Clubs'), ('', 'Diamonds')]

I know this is an old question and was already answered, but for some reason, I still wanna post this alternative solution. I know it’s easy to just find out which built-in function does the “magic” you need, but it doesn’t hurt to know you can do it by yourself.

>>> list_1 = ['Ace', 'King']
>>> list_2 = ['Spades', 'Clubs', 'Diamonds']
>>> deck = []
>>> for i in range(max((len(list_1),len(list_2)))):
        while True:
            try:
                card = (list_1[i],list_2[i])
            except IndexError:
                if len(list_1)>len(list_2):
                    list_2.append('')
                    card = (list_1[i],list_2[i])
                elif len(list_1)<len(list_2):
                    list_1.append('')
                    card = (list_1[i], list_2[i])
                continue
            deck.append(card)
            break
>>>
>>> #and the result should be:
>>> print deck
>>> [('Ace', 'Spades'), ('King', 'Clubs'), ('', 'Diamonds')]

回答 6

您在问题陈述中显示的输出不是元组而是列表

list_c = [(1,5), (2,6), (3,7), (4,8)]

检查

type(list_c)

考虑到您想要结果作为list_a和list_b中的元组,请执行

tuple(zip(list_a,list_b)) 

The output which you showed in problem statement is not the tuple but list

list_c = [(1,5), (2,6), (3,7), (4,8)]

check for

type(list_c)

considering you want the result as tuple out of list_a and list_b, do

tuple(zip(list_a,list_b)) 

回答 7

一种不使用的替代方法zip

list_c = [(p1, p2) for idx1, p1 in enumerate(list_a) for idx2, p2 in enumerate(list_b) if idx1==idx2]

万一不仅要获取元组1st与1st,2nd与2nd …而且要获取2个列表的所有可能组合,可以使用

list_d = [(p1, p2) for p1 in list_a for p2 in list_b]

One alternative without using zip:

list_c = [(p1, p2) for idx1, p1 in enumerate(list_a) for idx2, p2 in enumerate(list_b) if idx1==idx2]

In case one wants to get not only tuples 1st with 1st, 2nd with 2nd… but all possible combinations of the 2 lists, that would be done with

list_d = [(p1, p2) for p1 in list_a for p2 in list_b]

为什么Python中没有元组理解?

问题:为什么Python中没有元组理解?

众所周知,列表理解

[i for i in [1, 2, 3, 4]]

并且有字典理解,例如

{i:j for i, j in {1: 'a', 2: 'b'}.items()}

(i for i in (1, 2, 3))

最终将成为生成器,而不是tuple理解力。这是为什么?

我的猜测是a tuple是不可变的,但这似乎并不是答案。

As we all know, there’s list comprehension, like

[i for i in [1, 2, 3, 4]]

and there is dictionary comprehension, like

{i:j for i, j in {1: 'a', 2: 'b'}.items()}

but

(i for i in (1, 2, 3))

will end up in a generator, not a tuple comprehension. Why is that?

My guess is that a tuple is immutable, but this does not seem to be the answer.


回答 0

您可以使用生成器表达式:

tuple(i for i in (1, 2, 3))

但是对于…生成器表达式,已经使用了括号。

You can use a generator expression:

tuple(i for i in (1, 2, 3))

but parentheses were already taken for … generator expressions.


回答 1

Raymond Hettinger(Python核心开发人员之一)在最近的一条推文中曾这样说过元组:

#python提示:通常,列表用于循环;结构的元组。列表是同质的;元组异构。列出可变长度。

(对我来说)支持这样的想法:如果序列中的项目相关性足以由生成器生成,那么它应该是一个列表。尽管元组是可迭代的,并且看起来只是一个不可变的列表,但它实际上与C结构的Python等效:

struct {
    int a;
    char b;
    float c;
} foo;

struct foo x = { 3, 'g', 5.9 };

成为Python

x = (3, 'g', 5.9)

Raymond Hettinger (one of the Python core developers) had this to say about tuples in a recent tweet:

#python tip: Generally, lists are for looping; tuples for structs. Lists are homogeneous; tuples heterogeneous. Lists for variable length.

This (to me) supports the idea that if the items in a sequence are related enough to be generated by a, well, generator, then it should be a list. Although a tuple is iterable and seems like simply a immutable list, it’s really the Python equivalent of a C struct:

struct {
    int a;
    char b;
    float c;
} foo;

struct foo x = { 3, 'g', 5.9 };

becomes in Python

x = (3, 'g', 5.9)

回答 2

从Python 3.5开始,您还可以使用splat *解包语法来解压缩生成器表达式:

*(x for x in range(10)),

Since Python 3.5, you can also use splat * unpacking syntax to unpack a generator expresion:

*(x for x in range(10)),

回答 3

正如另一位发帖人macm所述,从生成器创建元组的最快方法是tuple([generator])


性能比较

  • 清单理解:

    $ python3 -m timeit "a = [i for i in range(1000)]"
    10000 loops, best of 3: 27.4 usec per loop
    
  • 来自列表理解的元组:

    $ python3 -m timeit "a = tuple([i for i in range(1000)])"
    10000 loops, best of 3: 30.2 usec per loop
    
  • 生成器中的元组:

    $ python3 -m timeit "a = tuple(i for i in range(1000))"
    10000 loops, best of 3: 50.4 usec per loop
    
  • 打开包装的元组:

    $ python3 -m timeit "a = *(i for i in range(1000)),"
    10000 loops, best of 3: 52.7 usec per loop
    

我的python版本

$ python3 --version
Python 3.6.3

因此,除非性能不是问题,否则应始终从列表理解中创建一个元组。

As another poster macm mentioned, the fastest way to create a tuple from a generator is tuple([generator]).


Performance Comparison

  • List comprehension:

    $ python3 -m timeit "a = [i for i in range(1000)]"
    10000 loops, best of 3: 27.4 usec per loop
    
  • Tuple from list comprehension:

    $ python3 -m timeit "a = tuple([i for i in range(1000)])"
    10000 loops, best of 3: 30.2 usec per loop
    
  • Tuple from generator:

    $ python3 -m timeit "a = tuple(i for i in range(1000))"
    10000 loops, best of 3: 50.4 usec per loop
    
  • Tuple from unpacking:

    $ python3 -m timeit "a = *(i for i in range(1000)),"
    10000 loops, best of 3: 52.7 usec per loop
    

My version of python:

$ python3 --version
Python 3.6.3

So you should always create a tuple from a list comprehension unless performance is not an issue.


回答 4

理解通过循环或迭代项并将它们分配到容器中来工作,元组无法接收分配。

创建元组后,将无法对其进行追加,扩展或分配。修改元组的唯一方法是是否可以将其对象之一本身分配给它(是非元组容器)。因为元组仅持有对此类对象的引用。

另外-元组有自己的构造函数tuple(),您可以提供任何迭代器。这意味着要创建一个元组,您可以执行以下操作:

tuple(i for i in (1,2,3))

Comprehension works by looping or iterating over items and assigning them into a container, a Tuple is unable to receive assignments.

Once a Tuple is created, it can not be appended to, extended, or assigned to. The only way to modify a Tuple is if one of its objects can itself be assigned to (is a non-tuple container). Because the Tuple is only holding a reference to that kind of object.

Also – a tuple has its own constructor tuple() which you can give any iterator. Which means that to create a tuple, you could do:

tuple(i for i in (1,2,3))

回答 5

我最好的猜测是,他们用完了括号,并认为这对警告添加“丑陋”语法没有足够的帮助…

My best guess is that they ran out of brackets and didn’t think it would be useful enough to warrent adding an “ugly” syntax …


回答 6

元组不能像列表一样有效地附加。

因此,元组理解将需要在内部使用列表,然后转换为元组。

那将与您现在所做的相同:tuple([comprehension])

Tuples cannot efficiently be appended like a list.

So a tuple comprehension would need to use a list internally and then convert to a tuple.

That would be the same as what you do now : tuple( [ comprehension ] )


回答 7

括号不会创建元组。又名一个=(两个)不是元组。唯一的解决方法是一个=(两个)或一个=元组(两个)。因此,解决方案是:

tuple(i for i in myothertupleorlistordict) 

Parentheses do not create a tuple. aka one = (two) is not a tuple. The only way around is either one = (two,) or one = tuple(two). So a solution is:

tuple(i for i in myothertupleorlistordict) 

回答 8

我相信这只是为了清楚起见,我们不想用太多不同的符号来使语言混乱。同样tuple也不需要理解,可以使用列表,而速度差异可以忽略不计,而不是像dict理解而不是list理解。

I believe it’s simply for the sake of clarity, we do not want to clutter the language with too many different symbols. Also a tuple comprehension is never necessary, a list can just be used instead with negligible speed differences, unlike a dict comprehension as opposed to a list comprehension.


回答 9

我们可以从列表理解中生成元组。下一个将两个数字顺序加到一个元组中,并给出一个从0-9的列表。

>>> print k
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
>>> r= [tuple(k[i:i+2]) for i in xrange(10) if not i%2]
>>> print r
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]

We can generate tuples from a list comprehension. The following one adds two numbers sequentially into a tuple and gives a list from numbers 0-9.

>>> print k
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
>>> r= [tuple(k[i:i+2]) for i in xrange(10) if not i%2]
>>> print r
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]