彭某的技术折腾笔记

彭某的技术折腾笔记

Python 装包与拆包

2024-05-17

Python 装包与拆包

2024年5月17日

摘要

在各种场景下的程序开发中,都时常会用到集合变量与普通变量之间的交互,有时会需要将集合变量拆散,有时会需要将一些变量装入一个集合。Python 在语法层面提供了非常方便的设计用来拆包和装包。本文将对其进行介绍。

Tuple 自动拆装包

Python 支持对元祖的自动拆包与装包,在以下场景中,只支持一个对象的操作,当出现多个变量与之对应时,将会自动装包,将多个变量生成一个 Tuple:

  • 函数返回值
  • 对象赋值

例如:

def func():
  return 1, 2, 3, 4

result = func()
# (1, 2, 3, 4)

此时,返回值的多个变量就被自动打包成了一个单一的 Tuple 对象传出。

赋值操作也是:

m = 1, 2, 3, 4
print(m)
# (1, 2, 3, 4)

a, b, c, d = m
print(a, b, c, d)
# 1 2 3 4

a, b = b, a
print(a, b)
# 2 1

总而言之,但凡赋值操作的任何一边有超过一个变量,都会被自动打包成 Tuple。

面对不同类型的 集合变量,都可以自动拆包:

a, b, c = (1, 2, 3)
# 1, 2, 3

a, b, c = [1, 2, 3]
# 1, 2, 3

a, b, c = {'x': 1, 'y': 2, 'z': 3}
# 'x', 'y', 'z'

对 Tuple 和 List 拆包都很直观,对 Dict 的拆包只保留 Keys。

* 拆包符号

这个部分我个人并不是很欣赏,因为很多规则都是语法层面的硬定义,并没有什么特别好的形象理解方法,只能做一个罗列了。

函数参数

在函数传入参数的定义上,可以使用 *args 来让 args 捕获多个输入参数,args 本身会以 Tuple 的形式存储。

def func_1(*args):
    print(args)
    print(*args)

func_1(1, 2, 3, 4, 5, 6)
# (1, 2, 3, 4, 5, 6)
# 1 2 3 4 5 6

def func_2(x, *args):
    print(x)
    print(args)
    print(*args)
  
func_2(1, 2, 3, 4, 5, 6, 7)
# 1
# (2, 3, 4, 5, 6, 7)
# 2 3 4 5 6 7

def func_3(x, *args, y):
    print(x)
    print(args)
    print(*args)
  
func_3(1, 2, 3, 4, 5, 6, y=7)
# 1
# (2, 3, 4, 5, 6)
# 2 3 4 5 6

其中,func_1func_2 都比较易懂,需要注意的是 func_3* 形式的拆包只能作为最后一个位置参数(Position Parameter),后面的就必须是带名字的关键字参数了(Keyword Parameter)。

变量赋值

在变量赋值上,语法规则就略有不同,但也是能够吸收多个变量,生成一个 List,而不是 Tuple:

a, *xs, b = 1, 2, 3, 4, 5, 6, 7
# a = 1
# xs = [2, 3, 4, 5, 6]
# b = 7

*ys = 1, 2, 3
# SyntaxError: starred assignment target must be in a list or tuple

此时,* 表达式可以不是最后一个元素,但不能是唯一一个元素,否则是一个语法错误。

至于为什么变量赋值的规则和函数参数不同,这真是单纯的语法规则。。

** 拆包符号

这个符号只对 Dict 有效,且至用于函数传参:

def func(a, b, c):
    print(a, b, c)

dict = {'a': 1, 'c': 3, 'b': 2}

func(**dict)
# 1 2 3

** 符号将把 dict 拆成 key_1=value_1, key_2=value_2, ... 的形式传入函数,由于都是关键字参数,所以位置不重要。

或是直接把函数参数定义为:

def func(**kwargs):
    print(kwargs)

dict = {'a': 1, 'b': 2, 'c': 3}

func(**dict)
# {'a': 1, 'b': 2, 'c': 3}
func(a=1, b=2, c=3)
# {'a': 1, 'b': 2, 'c': 3}

也可以混合使用:

def func(x, *args, **kwargs):
    print(x)
    print(args)
    print(kwargs)

list = [1, 2, 3]
dict = {'a': 4, 'b': 5, 'c': 6}

func(0, *list, **dict)
# 0
# (1, 2, 3)
# {'a': 4, 'b': 5, 'c': 6}
  • 0