我知道我可以通过这两种方法创建一个元组:
tuple([1, 2, 3])
(1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
我试图了解这里到底发生了什么:
tuple( (x, x*x) for x in [1, 2, 3] )
Run Code Online (Sandbox Code Playgroud)
元组构造函数似乎需要一个列表,但下面的代码似乎不会生成一个列表
(x, x*x) for x in [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)
我也想知道为什么这不起作用:
( (x, x*x) for x in [1, 2, 3] )
Run Code Online (Sandbox Code Playgroud)
对于字典,我似乎可以使用:
my_dict = dict()
my_dict = {}
Run Code Online (Sandbox Code Playgroud)
但现在我想知道是否像元组一样存在差异。是():tuple()一种不同的::关系吗{}:dict()?
Par*_*ngh 10
让我们来分析一下这里发生了什么。元组构造函数似乎想要一个列表,这并没有错,但更准确地说,元组构造函数似乎想要一个类似列表的对象。(具体来说,任何可迭代的作品)
这是一种称为“鸭子打字”的哲学。
俗话说:
如果它走路像鸭子,游泳像鸭子,嘎嘎叫像鸭子,那么它可能就是鸭子。
那么,列表就可以了
a = [1, 2, 3, 2]
tuple(a) #Output: (1, 2, 3, 2)
Run Code Online (Sandbox Code Playgroud)
但不同的可迭代对象也是如此,例如集合
tuple(set(a)) #Output: (1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
因此,元组并不关心它接收到的对象是否是列表,只是它应该能够迭代并从对象中获取值。
现在,魔法的第二部分来自于所谓的列表理解/生成器表达式。它们是您可以创建的迭代,可以轻松编写分别创建列表或生成器表达式的 1 个衬垫。稍后将详细介绍生成器,现在,了解列表理解如何工作就足够了。
列表理解的简单示例
[a for a in range(4)] #Output: [0, 1, 2, 3]
[a*a for a in range(4)] #output: [0, 1, 4, 9]
Run Code Online (Sandbox Code Playgroud)
我们看到他们生成了列表。那么,我们可以将它们提供给元组构造函数吗?为什么不!
tuple([a for a in range(4)]) #Output: (0, 1, 2, 3)
tuple([a*a for a in range(4)]) #output: (0, 1, 4, 9)
Run Code Online (Sandbox Code Playgroud)
现在,使用相同的表达式但将其括在弯括号中怎么样?
(a for a in range(4)) #Output: <generator object <genexpr> at 0x000000FA4FDBE728>
Run Code Online (Sandbox Code Playgroud)
您刚刚创建了一个生成器表达式
它们本质上是内存高效的按需迭代。(具体来说,它们有一个 Yield 和 next ,并且只有需要时的 Yield 值)。让我们看看它的实际效果。
my_generator = (a for a in range(4)) #generator created.
next(my_generator) #Outputs 0
next(my_generator) #Outputs 1
next(my_generator) #outputs 2
next(my_generator) #outputs 3
next(my_generator) #Raises StopIteration Error. The generator is exhausted.
Run Code Online (Sandbox Code Playgroud)
我们可以看到我们收到了与列表理解相同的值。那么,元组是否接受类似生成器之类的东西?好吧,鸭子打字来救援!绝对地!
tuple((a for a in range(4))) #Output: (0, 1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
我需要多余的括号吗?没有!
tuple(a for a in range(4)) #Output: (0, 1, 2, 3)
tuple(a*a for a in range(4)) #Output: (0, 1, 4, 9)
Run Code Online (Sandbox Code Playgroud)
现在,这会产生什么?(x, x*x) for x in [1, 2, 3]
嗯,它是一个表达式,但让我们了解一下它在列表理解中的样子
[(x, x*x) for x in [1, 2, 3]] #Output: [(1, 1), (2, 4), (3, 9)]
Run Code Online (Sandbox Code Playgroud)
啊,它是一个元组列表?发电机可以做同样的事情吗?
my_generator = ((x, x*x) for x in [1, 2, 3]) #<generator object <genexpr> at 0x000000FA4FD2DCA8>
next(my_generator) #Output: (1, 1)
next(my_generator) #Output: (2, 4)
next(my_generator) #Output: (3, 9)
next(my_generator) #Raises StopIteration
Run Code Online (Sandbox Code Playgroud)
是的,看起来不错。所以它是一个生成器,但它是一个可迭代的。不管怎样,它的行为就像一只鸭子,不是吗?所以,元组构造函数应该可以正常工作!
tuple((x, x*x) for x in [1, 2, 3]) #Output: ((1, 1), (2, 4), (3, 9))
Run Code Online (Sandbox Code Playgroud)
那么,这一切就结束了。括号并不总是暗示元组,() 不是为元组保留的。我们在这里看到它们也可以用于生成器表达式!同样,{} 不必始终与字典绑定,字典中实际上也存在类似于列表理解的东西!(称为字典理解)
我强烈建议您浏览链接,以更全面地解释此处协同工作的各个部分。希望这可以帮助!