我已经阅读了几个python教程(Dive Into Python,一个),以及Python.org上的语言参考 - 我不明白为什么语言需要元组.
与列表或集合相比,元组没有方法,如果我必须将元组转换为集合或列表以便能够对它们进行排序,那么首先使用元组有什么意义呢?
不变性?
为什么有人关心变量是否存在于内存中的不同位置而不是最初分配的位置?这整个Python的不变性业务似乎过分强调.
在C/C++中,如果我分配一个指针并指向一些有效的内存,我不关心地址的位置,只要在我使用它之前它不是null.
每当我引用该变量时,我都不需要知道指针是否仍然指向原始地址.我只是检查null并使用它(或不使用).
在Python中,当我分配一个字符串(或元组)将其分配给x时,然后修改字符串,为什么我关心它是否是原始对象?只要变量指向我的数据,那就重要了.
>>> x='hello'
>>> id(x)
1234567
>>> x='good bye'
>>> id(x)
5432167
Run Code Online (Sandbox Code Playgroud)
x 仍然引用我想要的数据,为什么有人需要关心它的id是相同还是不同?
Ale*_*lli 119
不可变对象可以允许实质性的优化; 这可能是为什么字符串在Java中也是不可变的,它是相当独立开发的,但与Python大致相同,而且几乎所有东西都是真正的函数式语言中不可变的.
特别是在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
Run Code Online (Sandbox Code Playgroud)
Gra*_*aul 40
上面的答案都没有指出元组与列表的真正问题,许多Python新手似乎都不完全理解.
元组和列表用于不同的目的.列表存储同质数据.您可以而且应该有这样的列表:
["Bob", "Joe", "John", "Sam"]
Run Code Online (Sandbox Code Playgroud)
正确使用列表的原因是因为这些都是同类数据,特别是人名.但是采取这样的列表:
["Billy", "Bob", "Joe", 42]
Run Code Online (Sandbox Code Playgroud)
该列表是一个人的全名和他们的年龄.这不是一种数据.存储该信息的正确方法是在元组中或在对象中.可以说我们有几个:
[("Billy", "Bob", "Joe", 42), ("Robert", "", "Smith", 31)]
Run Code Online (Sandbox Code Playgroud)
元组和列表的不变性和可变性不是主要区别.列表是相同类型的项目列表:文件,名称,对象.元组是不同类型对象的分组.它们有不同的用途,许多Python编码器滥用列表来表示元组的含义.
请不要.
编辑:
我认为这篇博文解释了为什么我认为这比我更好:http://news.e-scribe.com/397
out*_*tis 22
如果我必须将一个元组转换为一个集合或列表以便能够对它们进行排序,那么首先使用元组有什么意义呢?
在这种特殊情况下,可能没有意义.这不是问题,因为这不是您考虑使用元组的情况之一.
正如你所指出的,元组是不可变的.具有不可变类型的原因适用于元组:
请注意,特定的Python实现可能无法使用上述所有功能.
字典键必须是不可变的,否则更改键对象的属性可能会使底层数据结构的不变量无效.因此,元组可以用作键.这是const正确性的结果.
另请参阅Dive Into Python中的 " 介绍元组 " .
Joh*_*ooy 15
有时我们喜欢使用对象作为字典键
对于它的价值,最近(2.6+)的元组增长index()和count()方法
我总是发现对于相同的基本数据结构(数组)有两个完全独立的类型是一个笨拙的设计,但在实践中不是一个真正的问题.(每种语言都有疣,包括Python,但这不是一个重要的.)
为什么有人关心变量是否存在于内存中的不同位置而不是最初分配的位置?这整个Python的不变性业务似乎过分强调.
这些是不同的东西.可变性与存储在内存中的位置无关; 它意味着它指向的东西不能改变.
Python对象在创建后不能更改位置,可变或不可更改.(更准确地说,id()的值不能改变 - 在实践中也是如此.)可变对象的内部存储可以改变,但这是一个隐藏的实现细节.
>>> x='hello'
>>> id(x)
1234567
>>> x='good bye'
>>> id(x)
5432167
Run Code Online (Sandbox Code Playgroud)
这不是修改("变异")变量; 它正在创建一个具有相同名称的新变量,并丢弃旧变量.与变异操作相比:
>>> a = [1,2,3]
>>> id(a)
3084599212L
>>> a[1] = 5
>>> a
[1, 5, 3]
>>> id(a)
3084599212L
Run Code Online (Sandbox Code Playgroud)
正如其他人所指出的,这允许使用数组作为字典的键,以及需要不变性的其他数据结构.
请注意,词典的键不必完全不可变.只有用作密钥的部分需要是不可变的; 对于某些用途,这是一个重要的区别.例如,您可以拥有一个表示用户的类,该类通过唯一的用户名比较相等性和哈希值.然后,您可以在类上挂起其他可变数据 - "用户已登录"等.由于这不会影响相等性或散列,因此将其用作字典中的键是可能且完全有效的.这在Python中并不常见; 我只是指出它,因为有几个人声称密钥需要"不可变",这只是部分正确.不过,我已经多次使用C++地图和集合.
正如gnibbler在评论中提出的那样,Guido有一个未被完全接受/赞赏的观点:"列表用于同类数据,元组用于异构数据".当然,许多反对者认为这意味着列表的所有元素应该是相同的类型.
我喜欢以不同的方式看待它,与过去其他人一样:
blue= 0, 0, 255
alist= ["red", "green", blue]
Run Code Online (Sandbox Code Playgroud)
请注意,我认为alist是同质的,即使是type(alist [1])!= type(alist [2]).
如果我可以改变元素的顺序,我的代码中不会出现问题(除了假设,例如"它应该被排序"),那么应该使用一个列表.如果不是(就像blue上面的元组中那样),那么我应该使用一个元组.
它们很重要,因为它们保证调用者不会改变它们传递的对象.如果你这样做:
a = [1,1,1]
doWork(a)
Run Code Online (Sandbox Code Playgroud)
来电者没有价值的保证一个电话后.然而,
a = (1,1,1)
doWorK(a)
Run Code Online (Sandbox Code Playgroud)
现在,作为调用者或此代码的读者,您知道a是相同的.您可以随时为此场景制作列表的副本并传递它,但现在您正在浪费周期而不是使用更具语义意义的语言构造.