【譯】Python初學者應該瞭解的星號(*)

做者: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個位置參數:firstsecond,2個關鍵詞參數:thirdfourth。位置參數不能省略,必須給全部的位置參數按照其正確的位置傳值。然而,對於關鍵詞參數,在定義函數的時候你能夠設置默認值,若是調用函數的時候省略了相應的實參,會以默認值做爲實參,即關鍵詞參數能夠省略。

如你所見,關鍵詞參數能夠省略,因此,它們就不能在未知參數前面進行聲明,若是按照下面的方式聲明參數,就必然拋出異常。

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語言中的星號(*),做爲一個操做符,它有不少用途,特別是在「收集參數」中,顯得很重要。可是,初學者容易在此處迷惑,因此,若是你是初學者,上面的內容要認真看一看。

原文連接:medium.com/understand-…

搜索技術問答的公衆號:老齊教室

在公衆號中回覆:老齊,可查看全部文章、書籍、課程。

相關文章
相關標籤/搜索