做者:mingrammerpython
翻译:老齐编程
与本文相关的图书推荐:《Python大学实用教程》bash
与其余编程语言相比,Python语言的操做类型更多样化。markdown
特别是星号(*),在Python中是一个用途普遍的操做符,而不只仅用于两个数字相乘的运算之中。在本文中,咱们将讨论星号的多种用途。编程语言
这里总结了4种星号的应用场景:ide
下面逐一进行说明。函数
对此你必定不陌生,像乘法同样,Python中也内置了乘方运算符。oop
>>> 2 * 3
6
>>> 2 ** 3
8
>>> 1.414 * 1.414
1.9993959999999997
>>> 1.414 ** 1.414
1.6320575353248798
复制代码
Python也支持类列表的容器类对象(即序列)与整数相乘,即为按照整数实现重复其中的元素数量。spa
# Initialize the zero-valued list with 100 length zeros_list = [0] * 100 # Declare the zero-valued tuple with 100 length zeros_tuple = (0,) * 100 # Extending the "vector_list" by 3 times vector_list = [[1, 2, 3]] for i, vector in enumerate(vector_list * 3): print("{0} scalar product of vector: {1}".format((i + 1), [(i + 1) * e for e in vector])) # 1 scalar product of vector: [1, 2, 3] # 2 scalar product of vector: [2, 4, 6] # 3 scalar product of vector: [3, 6, 9] 复制代码
不少函数中,都会有不肯定个数的参数。例如,若是咱们不知道要提供多少个参数,或者由于什么缘由必须传任意个参数等。scala
在Python中有两类参数,一类是位置参数,另一类是关键词参数,前者根据位置肯定相应值,后者则是依据参数名称肯定。
在研究任意个位置/关键词参数以前,先讨论肯定数量的位置参数和关键词参数。
# A function that shows the results of running competitions consisting of 2 to 4 runners. def save_ranking(first, second, third=None, fourth=None): rank = {} rank[1], rank[2] = first, second rank[3] = third if third is not None else 'Nobody' rank[4] = fourth if fourth is not None else 'Nobody' print(rank) # Pass the 2 positional arguments save_ranking('ming', 'alice') # Pass the 2 positional arguments and 1 keyword argument save_ranking('alice', 'ming', third='mike') # Pass the 2 positional arguments and 2 keyword arguments (But, one of them was passed as like positional argument) save_ranking('alice', 'ming', 'mike', fourth='jim') 复制代码
上述代码中的函数有2个位置参数:first
、second
,2个关键词参数:third
、fourth
。位置参数不能省略,必须给全部的位置参数按照其正确的位置传值。然而,对于关键词参数,在定义函数的时候你能够设置默认值,若是调用函数的时候省略了相应的实参,会以默认值做为实参,即关键词参数能够省略。
如你所见,关键词参数能够省略,因此,它们就不能在未知参数前面进行声明,若是按照下面的方式声明参数,就必然抛出异常。
def save_ranking(first, second=None, third, fourth=None):
...
复制代码
可是,在save_ranking('alice', 'ming', 'mike', fourth='jim')
调用中,提供了3个位置实参和一个关键词参数。是的,对于关键词参数,你也能够按照位置参数的方式传值,所对应的关键词可以接受依据位置所传的数据。按照此处的调用方法,'mike'
就自动传给了third
。
以上咱们已经讨论了参数的基本含义,从上述示例中,咱们也能看出来,上面所定义的函数不能接收任意个数的参数,由于该函数的参数是固定数量的。所以,须要对该函数进行改造,让它可以接收任意个参数,不管是位置参数仍是关键词参数。看下面的示例:
def save_ranking(*args): print(args) save_ranking('ming', 'alice', 'tom', 'wilson', 'roy') # ('ming', 'alice', 'tom', 'wilson', 'roy') 复制代码
def save_ranking(*args, **kwargs): print(args) print(kwargs) save_ranking('ming', 'alice', 'tom', fourth='wilson', fifth='roy') # ('ming', 'alice', 'tom') # {'fourth': 'wilson', 'fifth': 'roy'} 复制代码
在上面的示例中,*args
意味着收集任意个数的位置参数,**kwargs
意味着收集任意个数的关键词参数。这里的*args
和**kwargs
能够称之为打包。
如你所见,在上面咱们按照位置或关键词传了任意个数的参数。按照位置传的参数被收集到元组中,并用变量args
引用;以关键词传的参数则用变量kwargs
引用为字典类型。
前面提到过,关键词参数不能写在位置参数前面,因此,下面的定义方式是错误的:
def save_ranking(**kwargs, *args):
...
复制代码
任意个数的参数颇有价值,在不少开源项目中都可以看到,通常都是用*args
或者**kwargs
做为收集任意参数的名称,固然,你能够用其余名称,好比*requeired
或者**optional
等,均可以。只是对于开源项目而言,咱们习惯使用*args
和**kwargs
罢了。
星号还能够用于对容器的解包,这与前面的参数收集相似,好比,有一个包含数据的列表、元组或者字典,还有一个收集任意参数的函数:
from functools import reduce primes = [2, 3, 5, 7, 11, 13] def product(*numbers): p = reduce(lambda x, y: x * y, numbers) return p product(*primes) # 30030 product(primes) # [2, 3, 5, 7, 11, 13] 复制代码
由于product()
能接收任意参数,咱们原本须要将列表中的元素取出来,而后传给此函数。但在这里,若是以*primes
的方式向函数提供primes
列表数据,则primes
所引用的列表会被解包,其中的每一个素数都被传给函数,并被收集后用变量numbers
引用。若是传该列表primes
给函数,就不能解包,numbers
所引用的元组中只有一个primes
列表。
对于元组也如此,对于字典,须要用**
代替*
。
headers = { 'Accept': 'text/plain', 'Content-Length': 348, 'Host': 'http://mingrammer.com' } def pre_process(**headers): content_length = headers['Content-Length'] print('content length: ', content_length) host = headers['Host'] if 'https' not in host: raise ValueError('You must use SSL for http communication') pre_process(**headers) # content length: 348 # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # File "<stdin>", line 7, in pre_process # ValueError: You must use SSL for http communication 复制代码
还有不少种解包的实现方式,甚至于不针对函数,只是从列表、元组中取出数据,并用动态变量引用。
numbers = [1, 2, 3, 4, 5, 6] # The left side of unpacking should be list or tuple. *a, = numbers # a = [1, 2, 3, 4, 5, 6] *a, b = numbers # a = [1, 2, 3, 4, 5] # b = 6 a, *b, = numbers # a = 1 # b = [2, 3, 4, 5, 6] a, *b, c = numbers # a = 1 # b = [2, 3, 4, 5] # c = 6 复制代码
上述操做中说明,能够分别从列表或元组中解包,获得相应值,而后用*a
和*b
引用解包所得数据,并将其打包为列表。这与前述任意个数的参数是一样的概念。
以上简要介绍了Python语言中的星号(*),做为一个操做符,它有不少用途,特别是在“收集参数”中,显得很重要。可是,初学者容易在此处迷惑,因此,若是你是初学者,上面的内容要认真看一看。
搜索技术问答的公众号:老齐教室
在公众号中回复:老齐,可查看全部文章、书籍、课程。