以下Python表达式有很大区别:
# First:
x,y = y,x+y
# Second:
x = y
y = x+y
如果输入x=1,y=2,那么first输出的是x=2,y=3,而second输出的是x=2,y=4
原因是python在赋值语句中,总是在对变量进行实际设置之前,先对等号右侧进行全面评估。比如 a, b = b ,a 先将等号右侧打包成元组 (b,a) ,再顺序地分给等号左侧的 a, b 变量。【元组不以()为标志,而是以 , 为标志】
因此第一个表达式:
第一个表达式实际上进行了下述操作,是元组的拆包功能简化了这一过程
ham = y
spam = x + y
x = ham
y = spam
Python中的元组tuple和列表list类似,不同之处在于:元组的元素不能修改,所以被称为不可变列表;在形式上,元组用小括号()表示,而列表用中括号[]表示;在计算过程中,元组的处理将比列表要快。
因为元组不能更改,如果要修改元组,我们只能通过变量进行重新赋值,不能进行元素的增删,否则会报错。
除了与列表类似的处理索引、截取、计算元组个数、最大值、最小值、长度、删除元组外,
len(tuple)
tuple.count(obj)
max(tuple)
min(tuple)
元组也有自己的函数,比如:
1.列表变元组,可以使用type()函数查看类型:
tuple('DNA')
tuple(['DNA','RNA','AA','peptide'])
2.元组拼接,比较一下以下两种不同的方法所获得元组:
tuple1 = ('DNA'), (['DNA','RNA','AA','peptide'])
tuple2 =('DNA') + (['DNA','RNA','AA','peptide'])
3.元组拆包
元组的拆包就是将元组内部的每个元素按照位置,对应的赋值给不同变量。
可以用于:变量赋值,变量值交换,函数参数赋值,获取元组中特定位置的元素值,等。此外,Python函数return多个对象,默认就是以tuple形式返回。
val=(10, 20)
a, b=val # 对元组拆包
print(a) # 10
print(b) # 20.5
不仅是元组, 在python中任何序列或可迭代对象(如:列表、元组、字符串、文件对象、迭代器和生成器等),皆可通过类似这样的简单赋值语句拆包给多个变量。
唯一的要求就是变量必须跟序列元素的数量一致,否则会抛出ValueError的异常( 但我们用 * 占位符来表示忽略多余的元素)
# 列表
>>> a,b,c = ['a', 'b', 'c']
>>> a
'a'
>>> a,b,c = enumerate(['a', 'b', 'c'])
>>> a
(0, 'a')
# 元组
>>> a,b,c = ('a', 'b', 'c')
>>> a
'a'
# 字典
>>> a,b,c = {'a':1, 'b':2, 'c':3}
>>> a
'a'
>>> a,b,c = {'a':1, 'b':2, 'c':3}.items()
>>> a
('a', 1)
# 字符串
>>> a,b,c = 'abc'
>>> a
'a'
# 生成器
>>> a,b,c = (x + 1 for x in range(3))
>>> a
1
可以利用占位符, 只拆分出我们需要的信息,忽略不需要的信息。
一般使用" _ "来代表一个占位符, 注:这是最常用最规范的,其实也可以使用任意变量名去占位,拆分后不管这部分变量即可。
>>> import os
>>> _, filename = os.path.split('/home/luciano/.ssh/idrsa.pub')
# os.path.split()函数就会返回以路径和最后一个文件组成的元组(path,last_part)
>>> filename
'idrsa.pub'
>>> info = ["Alice", 20, 168, 55, (1999,10,22)]
>>> _,age, height,_,_ = info
>>> age
20
>>> height
168
>>> _
(1999, 10, 22)
这里使用了 " _ " 占位,因为 " _ " 接收了多个值,所以最后打印变量 “_” 时,显示的是它最后一次拆分得到的(1999, 10, 22)。
一般使用 * 来代表多个占位符, 在python中, 函数用*args 来获取不确定数量的参数是一种经典写法。
*前缀只能用于一个变量名, 但是这个变量可以出现在赋值表达式的任意位置。 * 占位符拆出来的变量永远是list列表类型。
>>> *head, current = (1,3,5,7,9)
>>> head
[1, 3, 5, 7]
>>> current
9
>>> a, b, *c = range(5)
>>> a, b, c
(0, 1, [2, 3, 4])
上述例子中,不管拆包的数字有多少个,我们都能顺利取到该元组的最后一个元素。注意,这里的head和c都是list列表类型。
还有比如我们要计算平均分,去除最高分和最低分,除了用切片,还可以用拆包的方式获得中间的数值
>>> first, *new, last = [94, 85, 73, 46]
>>> new
[85, 73]
[剑指offer]反转链表, 比如将1->2->3->None的链表反转成3->2->1->None。
迭代的写法:
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
# 申请两个节点,pre和cur,pre指向None
pre = None
cur = head
# 遍历链表
while cur:
next = cur.next # 记录当前节点的下一个节点
cur.next = pre # 然后将当前节点指向pre
pre = cur # pre和cur节点都后移一位
cur = next
return pre
它的简化写法如下:
def reverseList(self, head):
prev = None
cur = head
while cur:
cur.next, pre, cur = pre, cur, cur.next
return pre
[剑指offer] 镜像二叉树, 迭代写法如下
class Solution:
def mirrorTree(self, root):
if not root: return None
## 备份,因为下一句改变了root.left,下一句需要用到原始值
tmp = root.left
root.left = self.mirrorTree(root.right)
root.right = self.mirrorTree(tmp)
return root
简化写法:
class Solution:
def mirrorTree(self, root):
if not root: return None
root.left, root.right = self.mirrorTree(root.right), self.mirrorTree(root.left)
return root
def myfun(a, b):
print(a + b)
#### 列表元组的拆包
>>> n = [1, 2]
>>> myfun(*n)
3
>>> m = (1, 2)
>>> myfun(*m)
3
#### 字典的拆包
>>> mydict = {'a':1, 'b': 2}
>>> myfun(**mydict)
3
>>> myfun(*mydict)
ba
常见应用:
>>> bob = {'name': 'Bob', 'age': 30}
>>> "{name}'s age is {age}".format(**bob)
"Bob's age is 30"
压包是拆包的逆过程,用zip函数实现
>>> a = ['a', 'b', 'c']
>>> b = [1, 2, 3]
>>> for i in zip(a, b):
... print(i)
...
('a', 1)
('b', 2)
('c', 3)