在許多情況下,您需要找到存儲在數(shù)據(jù)結(jié)構(gòu)中的項目數(shù)。Python 的內(nèi)置函數(shù)len()是幫助您完成此任務(wù)的工具。
在某些情況下, 的使用len()很簡單。但是,有時您需要更詳細(xì)地了解此函數(shù)的工作原理以及如何將其應(yīng)用于不同的數(shù)據(jù)類型。
Python 入門 len()
該函數(shù)len()是 Python 的內(nèi)置函數(shù)之一。它返回對象的長度。例如,它可以返回列表中的項目數(shù)。您可以將該函數(shù)用于許多不同的數(shù)據(jù)類型。但是,并非所有數(shù)據(jù)類型都是 的有效參數(shù)len()。
您可以從查看此功能的幫助開始:
>>> >>> help(len)Help on built-in function len in module builtins:len(obj, /) Return the number of items in a container.
該函數(shù)將一個對象作為參數(shù)并返回該對象的長度。該文件對len()去遠(yuǎn)一點:
返回對象的長度(項目數(shù))。參數(shù)可以是序列(例如字符串、字節(jié)、元組、列表或范圍)或集合(例如字典、集合或凍結(jié)集合)。(來源)
當(dāng)您使用內(nèi)置數(shù)據(jù)類型和許多帶有 的第三方類型時len(),該函數(shù)不需要遍歷數(shù)據(jù)結(jié)構(gòu)。容器對象的長度存儲為對象的屬性。每次在數(shù)據(jù)結(jié)構(gòu)中添加或刪除項目時,都會修改此屬性len()的值,并返回長度屬性的值。這確保了len()有效地工作。
在以下部分中,您將了解如何使用len()序列和集合。您還將了解一些不能用作len()Python 函數(shù)參數(shù)的數(shù)據(jù)類型。
使用len()內(nèi)置序列
一個序列是訂購物品的容器。列表、元組和字符串是 Python 中的三個基本內(nèi)置序列。您可以通過調(diào)用找到序列的長度len():
>>> >>> greeting = "Good Day!">>> len(greeting)9 >>> office_days = ["Tuesday", "Thursday", "Friday"]>>> len(office_days)3 >>> london_coordinates = (51.50722, -0.1275)>>> len(london_coordinates)2
在查找 string greeting、 listoffice_days和 tuple的長度時london_coordinates,您len()以相同的方式使用。所有三種數(shù)據(jù)類型都是 的有效參數(shù)len()。
該函數(shù)len()始終返回一個整數(shù),因為它正在計算您傳遞給它的對象中的項目數(shù)。0如果參數(shù)是空序列,則函數(shù)返回:
>>> >>> len("")0>>> len([])0>>> len(())0
在上面的例子中,你找到了一個空字符串、一個空列表和一個空元組的長度。該函數(shù)0在每種情況下都返回。
一個range對象也可以創(chuàng)建使用序列range()。一個range對象不存儲所有的值,但它們產(chǎn)生在需要時他們。但是,您仍然可以range使用len()以下方法找到對象的長度:
>>> >>> len(range(1, 20, 2))10
此數(shù)字范圍包括從1到19增量為的整數(shù)2。range對象的長度可以通過開始、停止和步長值來確定。
在本節(jié)中,您已將len()Python 函數(shù)用于字符串、列表、元組和range對象。但是,您也可以將該函數(shù)與任何其他內(nèi)置序列一起使用。
使用len()帶內(nèi)置集合
在某些時候,您可能需要在列表或其他序列中查找唯1項的數(shù)量。您可以使用集和len()來實現(xiàn)這一點:
>>> >>> import random >>> numbers = [random.randint(1, 20) for _ in range(20)] >>> numbers[3, 8, 19, 1, 17, 14, 6, 19, 14, 7, 6, 1, 17, 10, 8, 14, 17, 10, 2, 5] >>> unique_numbers = set(numbers){1, 2, 3, 5, 6, 7, 8, 10, 14, 17, 19} >>> len(unique_numbers)11
您numbers使用列表推導(dǎo)式生成列表,它包含 20 個介于1和之間的隨機(jī)數(shù)20。由于您生成的是隨機(jī)數(shù),因此每次運(yùn)行代碼時輸出都會不同。在這個特定的運(yùn)行中,有 20 個隨機(jī)生成的數(shù)字列表中有 11 個唯1數(shù)字。
您將經(jīng)常使用的另一種內(nèi)置數(shù)據(jù)類型是dictionary。在字典中,每一項都由一個鍵值對組成。當(dāng)您使用字典作為 的參數(shù)時len(),該函數(shù)返回字典中的項目數(shù):
>>> >>> len({"James": 10, "Mary": 12, "Robert": 11})3 >>> len({})0
第1個示例的輸出顯示此字典中有三個鍵值對。與序列的情況一樣,當(dāng)參數(shù)是空字典或空集時len()將返回0。這導(dǎo)致空字典和空集為假。
探索len()其他內(nèi)置數(shù)據(jù)類型
您不能使用所有內(nèi)置數(shù)據(jù)類型作為len(). 對于其中不存儲多個項目的數(shù)據(jù)類型,長度的概念不相關(guān)。這是數(shù)字和布爾類型的情況:
>>> >>> len(5)Traceback (most recent call last): ...TypeError: object of type 'int' has no len() >>> len(5.5)Traceback (most recent call last): ...TypeError: object of type 'float' has no len() >>> len(True)Traceback (most recent call last): ...TypeError: object of type 'bool' has no len() >>> len(5 + 2j)Traceback (most recent call last): ...TypeError: object of type 'complex' has no len()
該整數(shù),浮點數(shù),布爾,以及復(fù)雜類型的內(nèi)置數(shù)據(jù)類型,你不能使用示例len()。TypeError當(dāng)參數(shù)是沒有長度的數(shù)據(jù)類型的對象時,該函數(shù)會引發(fā) a 。
您還可以探索是否可以使用迭代器和生成器作為參數(shù)len():
>>> >>> import random >>> numbers = [random.randint(1, 20) for _ in range(20)]>>> len(numbers)20 >>> numbers_iterator = iter(numbers)>>> len(numbers_iterator)Traceback (most recent call last): ...TypeError: object of type 'list_iterator' has no len() >>> numbers_generator = (random.randint(1, 20) for _ in range(20))>>> len(numbers_generator)Traceback (most recent call last): ...TypeError: object of type 'generator' has no len()
您已經(jīng)看到列表具有長度,這意味著您可以將其用作len(). 您可以使用內(nèi)置函數(shù)從列表中創(chuàng)建一個迭代器iter()。在迭代器中,只要需要,就會獲取每個項目,例如在使用函數(shù)next()或在循環(huán)中時。但是,您不能在len().
你得到了TypeError,當(dāng)您嘗試使用一個迭代器作為一個參數(shù)len()。由于迭代器在需要時獲取每個項目,因此測量其長度的唯1方法是耗盡迭代器。迭代器也可以是無限的,例如由 返回的迭代器itertools.cycle(),因此它的長度無法定義。
不能使用發(fā)電機(jī)與len()出于同樣的原因。如果不使用它們,就無法測量這些物體的長度。
len()用一些例子進(jìn)一步探索
在本節(jié)中,您將了解len(). 這些示例將幫助您更好地了解何時使用此功能以及如何有效地使用它。在某些示例中,您還將看到len()可能的解決方案但可能有更多 Pythonic 方法來實現(xiàn)相同輸出的情況。
驗證用戶輸入的長度的一個常見用例len()是驗證用戶輸入的序列的長度:
# username.py username = input("Choose a username: [4-10 characters] ") if 4 <= len(username) <= 10: print(f"Thank you. The username {username} is valid")else: print("The username must be between 4 and 10 characters long")
在此示例中,您使用if語句來檢查 返回的整數(shù)len()是否大于或等于4且小于或等于10。你可以運(yùn)行這個腳本,你會得到一個類似于下面的輸出:
$ python username.pyChoose a username: [4-10 characters] stephen_gThank you. The username stephen_g is valid
在這種情況下,用戶名的長度為 9 個字符,因此if語句中的條件計算結(jié)果為True。您可以再次運(yùn)行腳本并輸入無效的用戶名:
$ python username.pyChoose a username: [4-10 characters] sgThe username must be between 4 and 10 characters long
在這種情況下,len(username)返回2,并且if語句中的條件計算結(jié)果為False。
根據(jù)對象的長度結(jié)束循環(huán)
len()如果您需要檢查可變序列(例如列表)的長度何時達(dá)到特定數(shù)字,您將使用。在以下示例中,您要求用戶輸入三個用戶名選項,并將它們存儲在列表中:
# username.py usernames = [] print("Enter three options for your username") while len(usernames) < 3: username = input("Choose a username: [4-10 characters] ") if 4 <= len(username) <= 10: print(f"Thank you. The username {username} is valid") usernames.append(username) else: print("The username must be between 4 and 10 characters long") print(usernames)
您現(xiàn)在使用的從結(jié)果len()的while聲明。如果用戶輸入了無效的用戶名,您不會保留輸入。當(dāng)用戶輸入有效字符串時,您將其附加到列表中usernames。循環(huán)重復(fù),直到列表中有三個項目。
您甚至可以len()用來檢查序列何時為空:
>>> >>> colors = ["red", "green", "blue", "yellow", "pink"] >>> while len(colors) > 0:... print(f"The next color is {colors.pop(0)}")...The next color is redThe next color is greenThe next color is blueThe next color is yellowThe next color is pink
您使用 list 方法.pop()在每次迭代中從列表中刪除第1項,直到列表為空。如果您在大型列表上使用此方法,則應(yīng)從列表末尾刪除項目,因為這樣效率更高。您還可以使用內(nèi)置模塊中的deque數(shù)據(jù)類型collections,它允許您有效地從左側(cè)彈出。
通過使用序列的真實性,有一種更 Pythonic 的方式來實現(xiàn)相同的輸出:
>>> >>> colors = ["red", "green", "blue", "yellow", "pink"] >>> while colors:... print(f"The next color is {colors.pop(0)}")...The next color is redThe next color is greenThe next color is blueThe next color is yellowThe next color is pink
空列表是假的。這意味著該while語句將空列表解釋為False。非空列表是真實的,while語句將其視為True. 返回的值len()決定了序列的真實性。一個序列是truthy當(dāng)len()返回任何非零整數(shù),并且當(dāng)falsylen()返回0。
查找序列醉后一項的索引
想象一下,您想要生成一個范圍1為的隨機(jī)數(shù)序列,10并且您希望不斷向該序列添加數(shù)字,直到所有數(shù)字的總和超過21。以下代碼創(chuàng)建一個空列表并使用while循環(huán)填充列表:
>>> >>> import random >>> numbers = []>>> while sum(numbers) <= 21:... numbers.append(random.randint(1, 10)) >>> numbers[3, 10, 4, 7] >>> numbers[len(numbers) - 1]7 >>> numbers[-1] # A more Pythonic way to retrieve the last item7 >>> numbers.pop(len(numbers) - 1) # You can use numbers.pop(-1)7 >>> numbers[3, 10, 4]
您將隨機(jī)數(shù)附加到列表中,直到總和超過21。當(dāng)您生成隨機(jī)數(shù)時,您將獲得的輸出會有所不同。要顯示列表中的醉后一個數(shù)字,請使用它len(numbers)并1從中減去,因為列表的第1個索引是0。Python 中的索引允許您使用索引-1來獲取列表中的醉后一項。因此,雖然您可以len()在這種情況下使用,但您不需要。
您想刪除列表中的醉后一個數(shù)字,以便列表中所有數(shù)字的總和不超過21。您len()再次使用來計算列表中醉后一項的索引,您將其用作列表方法的參數(shù).pop()。即使在這種情況下,您也可以將其-1用作.pop()從列表中刪除醉后一項并返回它的參數(shù)。
將列表分成兩半
如果需要將序列分成兩半,則需要使用表示序列中點的索引。您可以使用len()來查找此值。在以下示例中,您將創(chuàng)建一個隨機(jī)數(shù)列表,然后將其拆分為兩個較小的列表:
>>> >>> import random >>> numbers = [random.randint(1, 10) for _ in range(10)]>>> numbers[9, 1, 1, 2, 8, 10, 8, 6, 8, 5] >>> first_half = numbers[: len(numbers) // 2]>>> second_half = numbers[len(numbers) // 2 :] >>> first_half[9, 1, 1, 2, 8]>>> second_half[10, 8, 6, 8, 5]
在定義 的賦值語句中first_half,使用表示從開頭numbers到中點的項目的切片。您可以通過分解切片表達(dá)式中使用的步驟來計算切片表示的內(nèi)容:
1. 首先,len(numbers)返回整數(shù)10。
2. 接下來,10 // 2在5使用整數(shù)除法運(yùn)算符時返回整數(shù)。
3. 醉后,0:5是一個切片,表示前五個項目,其索引0為4。請注意,端點被排除在外。
在下一個定義中second_half,在切片中使用相同的表達(dá)式。但是,在這種情況下,整數(shù)5表示范圍的開始。切片現(xiàn)在5:代表從索引5到列表末尾的項目。
如果您的原始列表包含奇數(shù)個項目,則其長度的一半將不再是整數(shù)。當(dāng)您使用整數(shù)除法時,您將獲得數(shù)字的下限。該列表first_half現(xiàn)在將比 少一項second_half。
您可以通過創(chuàng)建一個包含 11 個數(shù)字而不是 10 個數(shù)字的初始列表來嘗試這一點。結(jié)果列表將不再是一半,但它們將代表最接近拆分奇數(shù)序列的替代方法。
將len()函數(shù)與第三方庫一起使用
您還可以將 Pythonlen()與來自第三方庫的多種自定義數(shù)據(jù)類型結(jié)合使用。在本教程的醉后一節(jié)中,您將了解 的行為如何len()取決于類定義。在本節(jié)中,您將查看使用len()來自兩個流行的第三方庫的數(shù)據(jù)類型的示例。
NumPy 的 ndarray
該NumPy的模塊是在Python編程的所有定量應(yīng)用的基石。該模塊介紹了numpy.ndarray數(shù)據(jù)類型。這種數(shù)據(jù)類型以及 NumPy 中的函數(shù)非常適合數(shù)值計算,并且是其他模塊中數(shù)據(jù)類型的構(gòu)建塊。
在開始使用 NumPy 之前,您需要安裝該庫。您可以使用 Python 的標(biāo)準(zhǔn)包管理器pip,并在控制臺中運(yùn)行以下命令:
$ python -m pip install numpy
您已經(jīng)安裝了 NumPy,現(xiàn)在您可以從列表中創(chuàng)建一個 NumPy 數(shù)組并len()在該數(shù)組上使用:
>>> >>> import numpy as np >>> numbers = np.array([4, 7, 9, 23, 10, 6])>>> type(numbers)
NumPy 函數(shù)從您作為參數(shù)傳遞的列表中np.array()創(chuàng)建一個類型的對象numpy.ndarray。
但是,NumPy 數(shù)組可以有多個維度。您可以通過將列表列表轉(zhuǎn)換為數(shù)組來創(chuàng)建二維數(shù)組:
>>> >>> import numpy as np >>> numbers = [ [11, 1, 10, 10, 15], [14, 9, 16, 4, 4],] >>> numbers_array = np.array(numbers)>>> numbers_arrayarray([[11, 1, 10, 10, 15], [14, 9, 16, 4, 4]]) >>> len(numbers_array)2 >>> numbers_array.shape(2, 5) >>> len(numbers_array.shape)2 >>> numbers_array.ndim2
該列表numbers由兩個列表組成,每個列表包含五個整數(shù)。當(dāng)您使用此列表列表創(chuàng)建 NumPy 數(shù)組時,結(jié)果是一個包含兩行五列的數(shù)組。當(dāng)您將此二維數(shù)組作為參數(shù)傳遞給 中時,該函數(shù)返回數(shù)組中的行數(shù)len()。
要獲得兩個維度的大小,您可以使用屬性.shape,它是一個顯示行數(shù)和列數(shù)的元組。您可以通過使用.shape和len()或通過使用 屬性來獲取 NumPy 數(shù)組的維數(shù).ndim。
一般來說,當(dāng)你有一個任意維數(shù)的數(shù)組時,len()返回第1維的大?。?/b>
>>> >>> import numpy as np >>> array_3d = np.random.randint(1, 20, [2, 3, 4])>>> array_3darray([[[14, 9, 15, 14], [17, 11, 10, 5], [18, 1, 3, 12]], [[ 1, 5, 6, 10], [ 6, 3, 1, 12], [ 1, 4, 4, 17]]]) >>> array_3d.shape(2, 3, 4) >>> len(array_3d)2
在本例中,您將創(chuàng)建一個三維數(shù)組,其形狀為(2, 3, 4)其中每個元素都是1和之間的隨機(jī)整數(shù)20。這次您使用該函數(shù)np.random.randint()創(chuàng)建了一個數(shù)組。函數(shù)len()返回2,這是第1個維度的大小。
查看NumPy 教程:您在 Python 中進(jìn)入數(shù)據(jù)科學(xué)的第1步,了解有關(guān)使用 NumPy 數(shù)組的更多信息。
Pandas’ DataFrame
pandas庫中的DataFrame類型是另一種在許多應(yīng)用程序中廣泛使用的數(shù)據(jù)類型。
在使用 pandas 之前,您需要在控制臺中使用以下命令進(jìn)行安裝:
$ python -m pip install pandas
您已經(jīng)安裝了 pandas 包,現(xiàn)在您可以從字典創(chuàng)建一個 DataFrame:
>>> >>> import pandas as pd >>> marks = { "Robert": [60, 75, 90], "Mary": [78, 55, 87], "Kate": [47, 96, 85], "John": [68, 88, 69],} >>> marks_df = pd.DataFrame(marks, index=["Physics", "Math", "English"]) >>> marks_df Robert Mary Kate JohnPhysics 60 78 47 68Math 75 55 96 88English 90 87 85 69 >>> len(marks_df)3 >>> marks_df.shape(3, 4)
字典的鍵是代表班級學(xué)生姓名的字符串。每個鍵的值是一個列表,其中包含三個主題的標(biāo)記。當(dāng)您從此字典創(chuàng)建 DataFrame 時,您可以使用包含主題名稱的列表來定義索引。
DataFrame 有三行四列。該函數(shù)len()返回 DataFrame 中的行數(shù)。該DataFrame類型還有一個.shape屬性,您可以使用它來顯示 DataFrame 的第1個維度表示行數(shù)。
您已經(jīng)了解了如何len()使用許多內(nèi)置數(shù)據(jù)類型以及來自第三方模塊的一些數(shù)據(jù)類型。在下一節(jié)中,您將學(xué)習(xí)如何定義任何類,以便將其用作len()Python 函數(shù)的參數(shù)。
您可以在The Pandas DataFrame: Make Working With Data Delightful 中進(jìn)一步探索 pandas 模塊。
使用len()用戶定義的類
當(dāng)您定義一個類時,您可以定義的特殊方法之一是.__len__(). 這些特殊方法被稱為 dunder 方法,因為它們在方法名稱的開頭和結(jié)尾都有雙下劃線。Python 的內(nèi)置len()函數(shù)調(diào)用其參數(shù)的.__len__()方法。
在上一節(jié)中,您已經(jīng)看到了len()當(dāng)參數(shù)是一個 pandasDataFrame對象時的行為。此行為由類的.__len__()方法決定DataFrame,您可以在以下模塊的源代碼中看到pandas.core.frame:
class DataFrame(NDFrame, OpsMixin): # ... def __len__(self) -> int: """ Returns length of info axis, but here we use the index. """ return len(self.index)
此方法使用 返回 DataFrame.index屬性的長度len()。此 dunder 方法將 DataFrame 的長度定義為等于 DataFrame 中的行數(shù),如 所示.index。
您可以.__len__()通過以下玩具示例進(jìn)一步探索dunder 方法。您將定義一個名為YString. 此數(shù)據(jù)類型基于內(nèi)置字符串類,但類型對象YString賦予字母 Y 比所有其他字母更重要:
# ystring.py class YString(str): def __init__(self, text): super().__init__() def __str__(self): """Display string as lowercase except for Ys that are uppercase""" return self.lower().replace("y", "Y") def __len__(self): """Returns the number of Ys in the string""" return self.lower().count("y")
.__init__()方法YString使用.__init__()父str類的方法初始化對象。您可以使用函數(shù)來實現(xiàn)這一點super()。該.__str__()方法定義了對象的顯示方式。函數(shù)str()、print()和format()都調(diào)用此方法。對于此類,您將對象表示為全小寫字符串,但字母 Y 除外,它顯示為大寫。
對于這個玩具類,您將對象的長度定義為字符串中字母 Y 的出現(xiàn)次數(shù)。因此,該.__len__()方法返回字母 Y 的計數(shù)。
您可以創(chuàng)建一個類的對象YString并找到它的長度。用于上述示例的模塊名稱是ystring.py:
>>> >>> from ystring import YString >>> message = YString("Real Python? Yes! Start reading today to learn Python") >>> print(message)real pYthon? Yes! start reading todaY to learn pYthon >>> len(message) # Returns number of Ys in message4
您YString從類型對象創(chuàng)建類型對象str并使用 顯示對象的表示print()。然后將該對象message用作 的參數(shù)len()。這將調(diào)用類的.__len__()方法,結(jié)果是字母 Y 在 中的出現(xiàn)次數(shù)message。在這種情況下,字母 Y 出現(xiàn)了四次。
YString該類不是一個非常有用的類,但它有助于說明如何自定義 的行為len()以滿足您的需要。該.__len__()方法必須返回一個非負(fù)整數(shù)。否則,它會引發(fā)錯誤。
另一個特殊的方法是.__bool__()方法,它決定了如何將對象轉(zhuǎn)換為布爾值。該.__bool__()dunder方法通常不用于序列和集合定義。在這些情況下,該.__len__()方法確定對象的真實性:
>>> >>> from ystring import YString >>> first_test = "tomorrow">>> second_test = "today" >>> bool(first_test)True >>> bool(YString(first_test))False >>> bool(second_test)True >>> bool(YString(second_test))True
變量first_string中沒有 Y。如 的輸出所示bool(),該字符串為真,因為它非空。但是,當(dāng)您YString從此字符串創(chuàng)建類型的對象時,新對象是假的,因為字符串中沒有 Y 字母。因此,len()返回0。相反,變量second_string確實包含字母 Y,因此字符串和類型的對象YString都是真值。
您可以在 Python 3 中的面向?qū)ο缶幊?(OOP) 中閱讀有關(guān)使用面向?qū)ο缶幊毯投x類的更多信息。
結(jié)論
您已經(jīng)探索了如何使用len()來確定序列、集合和其他同時包含多個項目的數(shù)據(jù)類型(例如 NumPy 數(shù)組和 Pandas DataFrames)中的項目數(shù)量。
該len()Python函數(shù)是在許多程序中的關(guān)鍵工具。它的一些用途很簡單,但正如您在本教程中看到的那樣,此功能比最基本的用例要多得多。了解何時可以使用此功能以及如何有效地使用它將有助于您編寫更整潔的代碼。