[python] 元组拆包

文章目录

      • 引子
      • 元组
      • 元组的拆包
        • 变量赋值
        • 占位符的使用
        • 变量值交换
        • 函数参数赋值
      • 附:压包

引子

以下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 变量。【元组不以()为标志,而是以 , 为标志】

因此第一个表达式:

  1. 创建一个具有值的临时元组 y,x+y
  2. 分配给另一个临时元组
  3. 将元组提取为变量x和y

第一个表达式实际上进行了下述操作,是元组的拆包功能简化了这一过程

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)

你可能感兴趣的:(Python)