# 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)
###### 下一篇文章
- JavaBeginnersTutorial 中文系列教程
- Java 教程
- Java 教程 – 入門
- Java 的歷史
- Java 基礎知識:Java 入門
- jdk vs jre vs jvm
- public static void main(string args[])說明
- 面向初學者的 Java 類和對象教程
- Java 構造器
- 使用 Eclipse 編寫 Hello World 程序
- 執行順序
- Java 中的訪問修飾符
- Java 中的非訪問修飾符
- Java 中的數據類型
- Java 中的算術運算符
- Java 語句初學者教程
- 用 Java 創建對象的不同方法
- 內部類
- 字符串構建器
- Java 字符串教程
- Java 教程 – 變量
- Java 中的變量
- Java 中的局部變量
- Java 中的實例變量
- Java 引用變量
- 變量遮蓋
- Java 教程 – 循環
- Java for循環
- Java 教程 – 異常
- Java 異常教程
- 異常處理 – try-with-resources語句
- Java 異常處理 – try catch塊
- Java 教程 – OOPS 概念
- Java 重載
- Java 方法覆蓋
- Java 接口
- 繼承
- Java 教程 – 關鍵字
- Java 中的this關鍵字
- Java static關鍵字
- Java 教程 – 集合
- Java 數組教程
- Java 集合
- Java 集合迭代器
- Java Hashmap教程
- 鏈表
- Java 初學者List集合教程
- Java 初學者的Map集合教程
- Java 初學者的Set教程
- Java 初學者的SortedSet集合教程
- Java 初學者SortedMap集合教程
- Java 教程 – 序列化
- Java 序列化概念和示例
- Java 序列化概念和示例第二部分
- Java 瞬態與靜態變量
- serialVersionUID的用途是什么
- Java 教程 – 枚舉
- Java 枚舉(enum)
- Java 枚舉示例
- 核心 Java 教程 – 線程
- Java 線程教程
- Java 8 功能
- Java Lambda:初學者指南
- Lambda 表達式簡介
- Java 8 Lambda 列表foreach
- Java 8 Lambda 映射foreach
- Java 9
- Java 9 功能
- Java 10
- Java 10 獨特功能
- 核心 Java 教程 – 高級主題
- Java 虛擬機基礎
- Java 類加載器
- Java 開發人員必須知道..
- Selenium 教程
- 1 什么是 Selenium?
- 2 為什么要進行自動化測試?
- 3 Selenium 的歷史
- 4 Selenium 工具套件
- 5 Selenium 工具支持的瀏覽器和平臺
- 6 Selenium 工具:爭霸
- 7A Selenium IDE – 簡介,優點和局限性
- 7B Selenium IDE – Selenium IDE 和 Firebug 安裝
- 7C Selenium IDE – 突破表面:初探
- 7D Selenium IDE – 了解您的 IDE 功能
- 7E Selenium IDE – 了解您的 IDE 功能(續)。
- 7F Selenium IDE – 命令,目標和值
- 7G Selenium IDE – 記錄和運行測試用例
- 7H Selenium IDE – Selenium 命令一覽
- 7I Selenium IDE – 設置超時,斷點,起點
- 7J Selenium IDE – 調試
- 7K Selenium IDE – 定位元素(按 ID,名稱,鏈接文本)
- 7L Selenium IDE – 定位元素(續)
- 7M Selenium IDE – 斷言和驗證
- 7N Selenium IDE – 利用 Firebug 的優勢
- 7O Selenium IDE – 以所需的語言導出測試用例
- 7P Selenium IDE – 其他功能
- 7Q Selenium IDE – 快速瀏覽插件
- 7Q Selenium IDE – 暫停和反射
- 8 給新手的驚喜
- 9A WebDriver – 架構及其工作方式
- 9B WebDriver – 在 Eclipse 中設置
- 9C WebDriver – 啟動 Firefox 的第一個測試腳本
- 9D WebDriver – 執行測試
- 9E WebDriver – 用于啟動其他瀏覽器的代碼示例
- 9F WebDriver – JUnit 環境設置
- 9G WebDriver – 在 JUnit4 中運行 WebDriver 測試
- 9H WebDriver – 隱式等待
- 9I WebDriver – 顯式等待
- 9J WebDriver – 定位元素:第 1 部分(按 ID,名稱,標簽名稱)
- 9K WebDriver – 定位元素:第 2 部分(按className,linkText,partialLinkText)
- 9L WebDriver – 定位元素:第 3a 部分(按cssSelector定位)
- 9M WebDriver – 定位元素:第 3b 部分(cssSelector續)
- 9N WebDriver – 定位元素:第 4a 部分(通過 xpath)
- 9O WebDriver – 定位元素:第 4b 部分(XPath 續)
- 9P WebDriver – 節省時間的捷徑:定位器驗證
- 9Q WebDriver – 處理驗證碼
- 9R WebDriver – 斷言和驗證
- 9S WebDriver – 處理文本框和圖像
- 9T WebDriver – 處理單選按鈕和復選框
- 9U WebDriver – 通過兩種方式選擇項目(下拉菜單和多項選擇)
- 9V WebDriver – 以兩種方式處理表
- 9W WebDriver – 遍歷表元素
- 9X WebDriver – 處理警報/彈出框
- 9Y WebDriver – 處理多個窗口
- 9Z WebDriver – 最大化窗口
- 9AA WebDriver – 執行 JavaScript 代碼
- 9AB WebDriver – 使用動作類
- 9AC WebDriver – 無法輕松定位元素? 繼續閱讀...
- 10A 高級 WebDriver – 使用 Apache ANT
- 10B 高級 WebDriver – 生成 JUnit 報告
- 10C 高級 WebDriver – JUnit 報表自定義
- 10D 高級 WebDriver – JUnit 報告自定義續
- 10E 高級 WebDriver – 生成 PDF 報告
- 10F 高級 WebDriver – 截屏
- 10G 高級 WebDriver – 將屏幕截圖保存到 Word 文檔
- 10H 高級 WebDriver – 發送帶有附件的電子郵件
- 10I 高級 WebDriver – 使用屬性文件
- 10J 高級 WebDriver – 使用 POI 從 excel 讀取數據
- 10K 高級 WebDriver – 使用 Log4j 第 1 部分
- 10L 高級 WebDriver – 使用 Log4j 第 2 部分
- 10M 高級 WebDriver – 以無頭模式運行測試
- Vue 教程
- 1 使用 Vue.js 的 Hello World
- 2 模板語法和反應式的初探
- 3 Vue 指令簡介
- 4 Vue Devtools 設置
- 5 數據綁定第 1 部分(文本,原始 HTML,JavaScript 表達式)
- 6 數據綁定第 2 部分(屬性)
- 7 條件渲染第 1 部分(v-if,v-else,v-else-if)
- 8 條件渲染第 2 部分(v-if和v-show)
- 9 渲染列表第 1 部分(遍歷數組)
- 10 渲染列表第 2 部分(遍歷對象)
- 11 監聽 DOM 事件和事件修飾符
- 12 監聽鍵盤和鼠標事件
- 13 讓我們使用簡寫
- 14 使用v-model進行雙向數據綁定
- 15 表單輸入綁定
- 18 類綁定
- Python 教程
- Python 3 簡介
- Python 基礎知識 - 又稱 Hello World 以及如何實現
- 如何在 Windows 中安裝 python
- 適用于 Windows,Mac,Linux 的 Python 設置
- Python 數字和字符串
- Python 列表
- Python 集
- Python 字典
- Python 條件語句
- Python 循環
- Python 函數
- 面向對象編程(OOP)
- Python 中的面向對象編程
- Python 3 中的異常處理
- Python 3:猜數字
- Python 3:猜數字 – 回顧
- Python 生成器
- Hibernate 教程
- Hibernate 框架基礎
- Hibernate 4 入門教程
- Hibernate 4 注解配置
- Hibernate 4 的實體關系
- Hibernate 4 中的實體繼承模型
- Hibernate 4 查詢語言
- Hibernate 4 數據庫配置
- Hibernate 4 批處理
- Hibernate 4 緩存
- Hibernate 4 審計
- Hibernate 4 的并發控制
- Hibernate 4 的多租戶
- Hibernate 4 連接池
- Hibernate 自舉