说明
《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
Python 星号表达式(Starred Expression)的形式有 *
、*args
、**
和 **kwargs
,用于将可迭代的数据或者参数序列按一定的数据形式解析出来。
关于星号表达式的理解,可以简单地认为:
*iterable
和**dictionary
;*args
和 **kwargs
星号后为什么有变量名呢?因为在作为函数的参数时需要有变量名去使用,这两个变量名是约定俗成,你用别的也可以(不建议用别的)。马上进入例子:
h = 'gairuo' # 一个普通字符串,可以拆开(迭代)
[*h] # ['g', 'a', 'i', 'r', 'u', 'o'] 列表
{*h} # {'a', 'g', 'i', 'o', 'r', 'u'} 集合
# 将两个元组合并为一个元组
x,y = ('a','b'), (1,2)
(*x,*y) # ('a', 'b', 1, 2)
# 合并字典
x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
# 拆成字典(还是自己)
{**x}
# {'a': 1, 'b': 2}
{**x, **y} # 合并
# {'a': 1, 'b': 3, 'c': 4}
{**y, **x} # 换位置合并(其实字典一般不用在意位置)
# {'b': 2, 'c': 4, 'a': 1}
没看明白没关系,下边会详细介绍。
星号表达式一个最最要的作用是解包(unpack),解包就是把一个整体数据按每个元素拆开。
print(*[1], *[2,3], *(4, 5), 6)
# 1 2 3 4 5 6
dict(**{'x1': 0, 'x2': 1}, y=2, **{'z': 3})
# {'x1': 0, 'x2': 1, 'y': 2, 'z': 3}
上例中,第一个语句将两个列表和一个元组拆开,最终返回的是单个元素;第二行代码将字典拆开,拆开后它与其他字典的定义组成了一个新的字典,完成了字典合并的工作。
我们发现,解包操作有以下特点:
*a
,应该是 [*a]
);*iterable
和 **dictionary
对应解包的是无 key 的和 有 key (mapping)的;以下是一个利用 Pandas 的综合例子:
import pandas as pd
dict(**pd.Series([*'abcd'], index=[*'1234']))
# {'1': 'a', '2': 'b', '3': 'c', '4': 'd'}
构建 Series 时的索引和值都可以将字符串进行解包成列表,由于 Series 是一个有key (mapping)的数据结构,我们可以将其用两个星号解包成字典。
一些其他的例子,方便大家理解:
# 在元组、列表、集合和字典允许解包
*range(4), 4
# (0, 1, 2, 3, 4)
[*range(4), 4]
# [0, 1, 2, 3, 4]
{*range(4), 4}
# {0, 1, 2, 3, 4}
{'x': 1, **{'y': 2}}
# {'x': 1, 'y': 2}
# 在字典中后面的值将始终覆盖前面的值
{'x': 1, **{'x': 2}}
# {'x': 2}
{**{'x': 2}, 'x': 1}
# {'x': 1}
# 推导式
ranges = [range(i) for i in range(5)]
[[*item] for item in ranges]
# [[], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3]]
{i:[*item] for i, item in enumerate(ranges)}
# {0: [], 1: [0], 2: [0, 1], 3: [0, 1, 2], 4: [0, 1, 2, 3]}
a = [1,2]
'{}+{}={}'.format(*a, sum(a))
# '1+2=3'
合并:
a = [1, 2]
b = (3, 4)
c = a + b
# 报错
c = [*a, *b]
c
# [1, 2, 3, 4]
星号表达式在我们定义变量时也可以让我们的操作非常简便,利用它在给变量赋值时,可以将变量成为一个容器(catch-all)来容纳未分配有明确定义的内容。
a, *b, c = range(5)
a # 0
c # 4
b # [1, 2, 3]
以上,b 使用了星号表达式,就容纳了中间所有的元素形成了一个列表。这就实现了类似:
first, rest = seq[0], seq[1:]
first, *rest = seq # 效果同上
减少了代码量,更加便捷。对于更复杂的解包模式,新语法看起来更干净,不再需要笨拙的索引处理。
此外,如果右边的值不是列表,而是 iterable,则必须将其转换为列表才能进行切片。
定义函数时,经常会使用 *args
和 **kwargs
来声明元组变量(位置变量)和字典变量(关键字变量)。
args = [1, 3]
range(*args) # 这样就将两个位置变量传入
# range(1, 3)
def f(a, b, c, d):
print(a, b, c, d, sep = '&')
f(1,2,3,4)
# 1&2&3&4
f(*[1, 2, 3, 4])
# 1&2&3&4
其他更多讲解可以查看:Python 函数的参数 中可变参数相关的介绍。
优点有以下:
缺点:
注意:
特别要注意的是对于无限元素迭代器,千万不要用解包,用 next(),如:
import itertools
c = itertools.count(10, 2)
[*c] # ! 危险,会死循环,按Ctrl+C退出
更新时间:2022-05-18 22:37:32 标签:python 表达式 星号