<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # Python 生成器 > 原文: [https://javabeginnerstutorial.com/python-tutorial/python-generator/](https://javabeginnerstutorial.com/python-tutorial/python-generator/) 本文旨在為 python 生成器提供一些溫和的介紹,并希望能激發讀者為他們找到有趣的用法。 這是一個有點復雜的主題,包含許多小細節,因此我們將使用下面的約定來提供更多信息。 隨意跳過這些內容,因為它們不是理解所必需的,但是對于好奇的人,它們應該提供更多的見解。 ## 什么是生成器? 生成器是功能強大的編程工具,可用于對大型或計算昂貴的數據進行有效的迭代。 與其他迭代方法相比,它還擁有更簡單的代碼和更好的性能。 實現 python 生成器的主要方法是: * 生成器函數(在 Python 2.2 中添加) * 生成器表達式(在 Python 2.4 中添加) 首先了解一些核心概念是必不可少的,因此現在讓我們深入研究。 ## 迭代和可迭代對象 您可能已經知道, *迭代*只是重復代碼行的更正式術語,例如在`while`和`for`循環中。 基于*可迭代*對象的概念,Python 在該語言中內置了一種特別靈活的迭代方法,**經常在`for`循環中使用**。 每當我們以前談論`for `循環時,**它們始終對可迭代對象進行操作**。 可迭代的對象通常是序列類型,例如列表,范圍,元組或集合,在 Python 中,可迭代的對象意味著可以用`for`之類的東西來迭代對象。 ```py # These are all iterable objects that 'for' is operating on my_list = [1,2,3,"Python",4] my_tuple = (5,6,7,"Rocks") my_set = {8,9,10} for item in my_list: ??? print(item) for item in my_tuple: ??? print(item) for item in my_set: ??? print(item) for x in range(5): ??? print(x) ``` > 在幕后,我們將對象稱為“可迭代”這一事實意味著它公開了一個名為“`__iter__()`”的方法,該方法返回該對象的迭代器。 ## 迭代器 迭代器是控制可迭代對象上的循環行為的對象。 其目的是跟蹤到目前為止迭代已到達的位置。 當“`for`”函數和相關函數在可迭代對象上運行時,它們實際上首先要從該對象請求一個迭代器。 如果失敗,則將引發異常,否則,該迭代器將反復用于獲取序列中的下一項,直到序列用盡。 實際上,這意味著“`for`”可以循環可提供迭代器的任何對象,但不能在其他任何事情上循環。像`int`或`float`之類的對象不能與其一起使用,因為它們沒有實現正確的方法。 ```py # Example: for statement works over a list, but not over a float my_list = [3,5,7,9] my_float = 1.1 for item in my_list: ??? print(item) for item in my_float: ??? print(item) ``` ### 輸出 ```py 3 5 7 9 Traceback (most recent call last): ? File ".\examples\iterator_demo.py", line 23, in <module> ??? for item in my_float: TypeError: 'float' object is not iterable ``` > 迭代器可以跟蹤程序在循環中的位置,并在請求時提取下一個項目。 迭代器必須: * 創建時將其設置為循環。 * 實現必須返回下一項的`__next __()`方法 * 循環結束時,`__next__()`方法還必須引發`StopIteration()`異常。 通常,迭代器對象使用存儲在其屬性之一中的循環計數器或類似計數器來跟蹤其位置。 這是一個如何在實踐中使用的示例: * 創建一個迭代器:將循環計數器設置為零。 * 迭代器的`__next__()`稱為:檢查循環計數器 * 如果完成,則返回`StopIteration()`異常 * 如果還沒有完成,請增加循環計數器并返回下一個項目 ## 生成器細節 生成器可以看作是迭代器的經過改進的版本,旨在由程序員以更直觀的方式編寫,并使用更少的代碼。 生成器和迭代器之間存在細微的差異: * 生成器是一種特殊的迭代器 * 他們定義了類似行為的函數 * 他們跟蹤自己的內部狀態(例如局部變量),這與迭代器不同 > 為了擴展最后一點,迭代器在每次循環時都以新狀態開始-對`__next__()`的每次調用都是一個新的函數調用,需要自己設置并創建自己的狀態。 > > 生成器不需要執行一次以上的設置-它可以重用上一次調用中的狀態。 當運行相同的代碼數千次時,這將變得更加高效。 在以下各節中,我們將介紹如何實現生成器,為什么從中受益于生成器以及一些可用代碼示例。 **進一步閱讀**:本文檔中不涉及但與之緊密相關的高級主題包括: * 將值發送到生成器(“`send()`”方法) * 連接生成器(`yield from`表達式) * 并發/并行處理/協程 在本文結尾處的一些參考文獻中對它們進行了介紹,但是為了對所有這些概念進行很好的介紹,強烈建議特別使用 [Dave Beazley 的](http://www.dabeaz.com/generators-uk/)PPT。 ## 實現生成器 ### 生成器函數 生成器函數可能是在 Python 中實現生成器的最簡單方法,但與常規函數和循環相比,它們的學習曲線仍然稍高。 簡而言之,生成器函數是一種特殊的函數,可以在運行時逐個產生其結果,而不必等待完成并立即返回所有結果。 它們很容易發現,因為您會注意到,使用關鍵字“`yield`”返回值。 此處可以使用通常的“返回”,但只能退出該函數。 > 如果生成器沒有設法“*產生*”任何數據,但是擊中了“返回”,則調用者將返回一個空列表(`[]`) 以下是一些通常用于創建生成器函數的語法示例: ```py # Form 1 - Loop through a collection (an iterable) and apply some processing to each item def generator_function(collection): ??? #setup statements here if needed ??? for item in collection: ??????? #do some processing ??????? return_value = apply_something_processing_to(item) ??????? yield return_value # Form 2 - Set up an arbitrary loop and return items that are generated by that - similar to range() function def generator_function(start,stop,step): ??? #setup statements here ??? loop_counter = <initial value based on start> ??? loop_limit = <final value based on stop> ??????? #might need to add one to limit to be inclusive of final value ??? loop_step = <value to increment counter by, based on step> ??????? #step could be negative, to run backwards ??? while loop_counter != loop_limit: ??????? #do some processing ??????? return_value = generate_item_based_on(loop_counter) ??????? #increment the counter ??????? loop_counter += loop_step ??????? yield return_value # Form 3 - Illustrates return mechanism - imagine the processing we're doing requires some kind of setup beforehand, perhaps connecting to a network resource def generator_function(collection): ??? #setup statements here if needed ??? setup_succeeded = do_some_setup() ??? if setup_succeeded: ??????? for item in collection: ??????????? #do some processing ??????????? return_value = apply_something_processing_to(item) ??????????? yield return_value ??? else: ??????? return ``` 如注釋中所述,第一種形式逐步遍歷可迭代的項目集合,并對每個項目進行某種處理,然后再“`yield`”。 雖然不是很令人興奮,但對于簡單的舊迭代當然可以實現,但是它的強大之處在于它可以成為其他生成器鏈的一部分。 由于每個項目需要更多的處理,生成器很快變得易于維護代碼。 第二種形式是一個示例,可以適用于生成任意長度的值的序列,支持無限序列或無限循環序列等。 例如,該機制在處理數學或科學問題時非常有用。 這是調用生成器函數的一些示例語法: ```py #Form 1 - more readable my_generator = generator_function(arguments) for result in my_generator: ??? output(result) #Form 2 - more concise for result in generator_function(arguments): ??? output(result) ``` 在第一種形式中,在第一條語句中設置了生成器,并將對它的引用存儲在變量中。 然后由以下“`for`”循環使用(或使用)它。 在第二種形式中,不存儲生成器,而是由“`for`”循環立即使用生成器。 #### 實踐中的生成器函數 這是說明創建和使用簡單生成器函數的示例。 它將文本文件過濾為僅包含特定字符串的行。 它還顯示了三種稍微不同的調用生成器的方式,有關詳細信息,請參見注釋: ```py #Example: Generator Functions def filtered_text(text_lines,wanted_text): ??? """ Compares each line in text_lines to wanted_text ??????? Yields the line if it matches """ ??? for line in text_lines: ??????? if wanted_text in line: ??????????? yield line #slow method - read whole file into memory, then use the generator to filter text #need to wait for the whole file to load before anything else can begin #uses more memory #not much benefit here! with open("Programming_Books_List.txt",'r') as file_obj: ??? lots_of_text = file_obj.readlines() matches = filtered_text(lots_of_text,"Python") for match in matches: ??? print(match) #faster method - use the file object as an iterator, filter it with the generator #only needs to keep current line in memory #current line is only read directly before use #outputs each match directly after it is found (before the file has finished reading) with open("Programming_Books_List.txt",'r') as file_obj: ??? matches = filtered_text(file_obj,"Python") ??? for match in matches: ??????? print(match) #sleeker method - this is doing the same as the faster method above, but in fewer lines of code #instead of storing the generator object in a variable, it is immediately used in a for loop #this is perhaps less readable, so it can be harder to debug with open("Programming_Books_List.txt",'r') as file_obj: ??? for match in filtered_text(file_obj,"Python"): ??????? print(match) ``` ### 生成器表達式 生成器表達式是創建簡單生成器函數的另一種方法。 這些趨向于更加簡潔,通常導致單行代碼,但并不總是像生成器函數那樣可讀。 它們的主要缺點是它們不如生成器函數靈活。 很難在生成器表達式中實現任何特別復雜的操作,因為您限于可以在單個表達式中輕松編寫的內容。 一些示例語法可能會有所幫助: ```py #Form 1: basic form - iterate over all items, run some processing on each new_generator = (apply_processing to(item) for item in iterable) #Form 2: filter - rejects items if the condition is not true new_generator = (item for item in iterable if condition) #Form 3: combination of forms 1 and 2 new_generator = (apply_processing to(item) for item in iterable if condition) ``` 它們看起來類似于列表推導,但實際上,列表推導會在返回之前將其整個輸出構建到內存中的列表中,而生成器表達式一次只會返回其輸出一項。 創建生成器后,即可使用與使用生成器函數幾乎相同的方式來使用(或使用)生成器。 這里有一些示例: ```py #Form 1 - more readable my_generator = (apply_processing to(item) for item in iterable) for result in my_generator: ??? output(result) #Form 2 - more concise for result in (apply_processing to(item) for item in iterable): ??? output(result) ``` #### 實踐中的生成器表達式 這是上一本書的清單示例,使用表格 2 進行了覆蓋: ```py #Example: Generator Expressions with open("Programming_Books_List.txt",'r') as file_obj: ??? for match in (line for line in file_obj if "Python" in line): ??????? print(match) ``` 注意,**僅需要這三行**。 使用生成器函數執行此操作所需的最少行數為 7。 這要簡潔得多,并能生成精美的代碼,但不能在所有情況下都使用。 ## 為什么要使用生成器? 在以下情況下,生成器特別有用: 1. 對大量數據執行重復性任務,其中原始數據“僅需要一次” 2. 在長數據序列上執行計算(可能適合或可能不適合內存-甚至可能是無限的!) 3. 生成數據序列,其中僅應在需要時才計算每個項目(惰性求值) 4. 對數據流中的多個項目執行一系列相同的操作(在管道中,類似于 Unix 管道) 在第一種情況下,如果數據本身不需要存儲在內存中或再次引用,則生成器非常有效。 它們使程序員可以零碎地處理較小的數據塊,并逐一產生結果。 程序絕對不需要保留先前迭代中的任何數據。 生成器帶來的好處是: * 減少內存使用 * 比其他迭代方法更快的速度和更少的開銷 * 它們可以優雅地構造管道 在上一個書單搜索示例中,使用生成器并沒有真正對性能或資源使用帶來任何好處,因為這是一個非常簡單的用例,并且源數據不是很大。 而且,所需的處理非常少,以致于可以使用其他方法輕松實現。 但是,如果每行所需的處理復雜得多怎么辦? 也許是某種文本分析,自然語言處理或根據字典檢查單詞? 假設在該示例中,我們還希望獲取每個書名,在十個不同的在線書店中進行搜索,然后返回最便宜的價格。 然后,讓我們擴展源數據,例如我們將圖書清單替換為 Amazon 可用的每本圖書的副本。 在這樣的規模下,問題變得如此之大,以至于傳統的迭代將需要大量資源,并且相對難以以任何效率進行編碼。 在這種情況下,使用生成器將大大簡化代碼,并且意味著可以在找到第一個書名后立即開始處理。 此外,即使處理非常大的源文件,開銷也很小。 ## 基本用法 ### 無限序列 到目前為止,使用生成器生成斐波那契數列的一個相當陳詞濫調的示例在計算機科學教學界是一個古老的偏愛,但仍然值得一看。 這是代碼: ```py #Example: Fibonacci sequence using generators def fibonacci(limit): ??? """ Generate the fibonacci sequence, stop when ??????? we reach the specified limit """ ??? current = 0 ??? previous1 = 0 ??? previous2 = 0 ??? while current <= limit: ??????? return_value = current ??????? previous2 = previous1 ??????? previous1 = current ??????? if current == 0: ??????????? current = 1 ??????? else: ??????????? current = previous1 + previous2 ??????? yield return_value for term in fibonacci(144): ??? print(term) ``` 其輸出如下: ```py 0 1 1 2 3 5 8 13 21 34 55 89 144 ``` 這是一個非常瑣碎的用例,但它確實說明了一個事實,即生成器正在處理其本地變量中的前兩個值的存儲,并且這些值在迭代之間不會丟失。 沒有其他數據被存儲,因此該函數在整個生命周期(從第一個迭代到十萬次迭代)中將使用幾乎相同數量的內存。 ## 高級用法 ### 使用生成器作為管道 管道是可以看到生成器實際功率的地方。 它們可以通過簡單地將生成器鏈接在一起來實現,以使一個生成器的輸出傳遞到下一個生成器的輸入。 當需要對一組數據依次執行多項操作時,它們非常有用。 正如 Dave Beazley 的精彩演講(請參閱參考資料)中所指出的那樣,系統程序員可以充分利用生成器。 比茲利沒有產生任意的數學序列,而是演示了有用的技術,例如解析 Web 服務器日志,監視文件和網絡端口,遍歷文件和文件系統等等。 下面是我自己的示例,該示例混合使用了生成器函數和表達式來對多個文件執行文本搜索。 我將其設置為在當前目錄的所有 Python 文件中搜索字符串“`# TODO:`”。 > 每當我在代碼中發現問題時,或者有一個以后想實現的想法時,我都想使用該表示法在盡可能靠近需要的地方插入待辦事項。 > > 它通常派上用場,但是在處理包含大量文件的大型項目時,這些說明可能會丟失! 這個示例有點費解,可以通過使用正則表達式(很有可能還有其他庫或 OS 函數)進行改進,但是作為一個純 Python 演示,它應該說明使用生成器可以實現的一些功能: ```py # pipeline_demo.py #Example: Search for "# TODO:" at start of lines in Python # files, to pick up what I need to work on next import os def print_filenames(filenames): ??? """Prints out each filename, and returns it back to the pipeline""" ??? for filename in filenames: ??????? print(filename) ??????? yield filename def file_read_lines(filenames): ??? """Read every line from every file""" ??? for filename in filenames: ??????? with open(filename,'r') as file_obj: ??????????? for line in file_obj: ??????????????? yield line #get a list of all python files in this directory filenames_list = os.listdir(".") #turn it into a generator filenames = (filename for filename in filenames_list) #filter to only Python files (*.py) filenames = (filename for filename in filenames if filename.lower().endswith(".py")) #print out current file name, then pop it back into the pipeline filenames = print_filenames(filenames) #pass the filenames into the file reader, get back the file contents file_lines = file_read_lines(filenames) #strip out leading spaces and tabs from the lines file_lines = (line.lstrip(" \t") for line in file_lines) #filter to just lines starting with "# TODO:" filtered = (line for line in file_lines if line.startswith("# TODO:")) #strip out trailing spaces, tabs and newlines filtered = (line.rstrip() for line in filtered) #display output for item in filtered: ??? print(item) # TODO: Write generator example # TODO: Test on current folder ??? # TODO: Test on a line indented with spaces ??????????? # TODO: Test on a line indented with tabs # TODO: Add more TODOs ``` 輸出: ```py test-TODOs.py # TODO: Test finding a TODO in another file test-noTODOs.py pipeline_demo.py # TODO: Write generator example # TODO: Test on current folder # TODO: Test on a line indented with spaces # TODO: Test on a line indented with tabs # TODO: Add more TODOs ``` 這個想法可以進一步發展-如上所述,在系統編程中,甚至在系統管理空間中,都有無數的用例。 如果需要管理服務器上的日志文件,則這種技術將非常有價值。 請參閱以下參考資料,以獲取有關該主題的更多信息和一些出色的示例。 您可以在 [JBTAdmin Github 上獲得與本文相關的所有代碼](https://github.com/JBTAdmin/python/tree/master/Generator%20Examples)。 ## 參考書目/進一步閱讀 標題:Python Wiki – 生成器 作者:多個 來源: [Python Wiki](https://wiki.python.org/moin/Generators) 標題:Python Wiki – 迭代器 Authors: Multiple 來源: [Python Wiki](https://wiki.python.org/moin/Iterator) 標題:Python 生成器 作者:斯科特·羅賓遜 資料來源:[濫用棧網站](http://stackabuse.com/python-generators/) 標題:Python 實踐手冊 – 第 5 章。迭代器&生成器 作者:Anand Chitipothu 資料來源: [Python 實踐手冊網站](https://anandology.com/python-practice-book/iterators.html) 標題:系統程序員的生成器技巧 – 版本 2.0 作者:David M. Beazley 資料來源: [David Beazley 的網站](http://www.dabeaz.com/generators-uk/) 標題:Python 生成器的 2 大好處(以及它們如何永久改變了我) 作者:亞倫·麥克斯韋(Aaron Maxwell) 來源: [O’Reilly 網站](https://www.oreilly.com/ideas/2-great-benefits-of-python-generators-and-how-they-changed-me-forever) ###### 下一篇文章
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看