
先来自测一下:
a = 3 * 2 # 太简单了
b = 3 ** 2 # 还是太简单了
c = 2 * 2 ** 2 ** 3 # 注意细节!极易出错!
def func(x, /, y, *, z, **kwargs): # 这个函数的参数什么意思?
pass
d, *e, f = range(10) # 问 e 的类型是什么?值是什么?
g = *range(10), 50 # g 的值是什么?
h = {'age': 18, 'name': 'XN'}
i = {'job': 'stu', 'net_name': '小倪同学0v0'}
j = {**h, **i} # 这里在干嘛?
*k, (l, m) = (1, 2, (3, 4))
*k, l, m = (1, 2, (3, 4)) # 这两个语句中 k, l, m 的值分别是什么? 答案:
a == 6
b == 9
c == 512
d == 0
e == [1, 2, 3, 4, 5, 6, 7, 8] # e 的类型是列表
f == 9
g == (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 50)
j == {'age': 18, 'name': 'XN', 'job': 'stu', 'net_name': '小倪同学0v0'} # 在做字典合并
# 倒数第二行
k == [1, 2]
l == 3
m == 4
# 最后一行
k == [1]
l == 2
m == (3, 4) 如果你感到犹豫,请接着往下看吧。

a * b 代表乘法,如 3 * 2 得到 6
a ** b 代表乘方,如 3 ** 2 得到 9
x ** y <==> pow(x, y) x ** y % z <==> pow(x, y, z)
细节:先算乘方后算乘法,且同为乘法从左向右,同为乘方从右向左。所以开头的 c 的值是 512 而不是 128,更不是 65536
函数定义时:
*args 这种写法,称为可变长位置参数。
额外的位置参数将“吸入”这个args,args是一个元组。
**kwargs 这种写法,称为可变长关键字参数。
额外的关键字参数将以键值对的形式“吸入”这个kwargs中,kwargs是一个字典。
注意:可变长关键字参数 和 可变长位置参数都至多存在一个
以上两种参数,统称可变长参数
且 *args 必须在 **kwargs 前面
def f(a, *, b): pass这种写法
将后面的所有参数设置为 keyword only argument,即只能用关键字传参。
这里的 a 两种传参都可以,而 b 只能使用关键字传参。为什么?因为这个 * 虽然没有参数名字,但它将所有额外的位置参数都“吸入”这个 * 里,所以 b 只能用关键字传参
序列解包 / 拆包
*args 将一个序列展开
**kwargs 将一个字典以键值对形式展开(其实不止字典,任何 mapping 都可以,常见的还有 collections.defaultdict, collections.OrderedDict 以及 collections.Counter 等)
e.g.
def add(x, y):
return x + y
nums_tuple = (2, 3)
add(nums_tuple[0], nums_tuple[1]) # 传统做法,返回 5
add(*nums_tuple) # 一个星号序列解包,返回 5
nums_dict = {'x': 2, 'y': 3}
add(x=nums_dict['x'], y=nums_dict['y']) # 传统做法,返回 5
add(**nums_dict) # 两个星号关键字解包,返回 5 不仅可以在函数调用时解包传参,也可用在赋值语句等。e.g.
a = *range(10), 50
# 把 range(10) 看成列表的话是 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 把它解包,在合并上后面的 50
# 得到 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 50)
# 注意,因为没加括号,默认是元组
a = [*range(10), 50]
# 但要是写成这样,就成了 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 50] 也可写在左值,用于拆包哦
a, *b, c = range(5)
# 这个例子中,range(5) 先解包成 (0, 1, 2, 3, 4)
# a 获取到一个 0
# 这个 b “能屈能伸”,先让 c 得到一个 4
# b 再把剩下的都吸入囊中,即 [1, 2, 3]
# (其实储存顺序是从前向后,这样说方便理解) 注意: 这样写出来的 b 是一个列表,不是元组
5. 正则表达式
匹配前面的子表达式 0 次或多次

二、斜杠的用途
a / b 代表 truediv,emmm...将其译为真除吧(网上没找到更好的翻译),返回浮点数,如 11 / 2 得到 5.5
a // b 代表floordiv,即整除,返回整数,如 11 // 2 得到 5
函数定义时,斜杠前面的参数成为 positional only argument,只能使用位置传参,不能使用关键字。e.g.
def add(a, b=0, /):
return a + b
# 可以这样调用
add(2) # 2
add(2, 1) # 3
# 不能这样调用
add(a=2) # TypeError
add(2, b=1) # TypeError 总结:
* 用于乘法、乘方等;也用于序列解包拆包;函数定义时作可变长参数标志,将其后面的参数设置为仅关键字参数
/ 用于 2 种除法;函数定义时将其前面的参数设置为仅位置参数

参考资料:
https://docs.python.org/3.8/tutorial/controlflow.html