1. 函式概述
在程式設計的語境下,函式 (function) 是指一個有命名的、執行某個計算的語句序列 (sequence of statements) 。函式可以針對某類問題建立通用解決步驟(演算法),函式減少了重複程式碼,從而讓程式更簡潔、易讀、易於操作。
函式由物件、語句、表示式組成。
函式執行特定的操作並返回一個值(無返回值則隱式返回 None)
函式程式設計是程式導向的。
Python函式程式碼結構和呼叫如下:
2. 變數
2.1 區域性作用域與全域性作用域、global語句
如果全域性作用域變數在區域性作用域沒有被定義(賦值,或者作為引數),則全域性作用域變數可以被區域性作用域讀取
>>> def func(): print(a) # 這種寫法是不好的 >>> a = 2 # a是全域性作用域變數,但可以被區域性作用域讀取 >>> func() 2
如果變數在區域性作用域中被定義了,則區域性作用域不會再讀取全域性作用域的變數,如果在變數被定義前讀取,則會引發錯誤,下面這個例子,Python 編譯函式的定義體時, 會先判斷 b 是區域性變數, 因為在函式中給它賦值了。
>>> b = 5 >>> def func(a): print(a) print(b) # 嘗試列印b變數出錯,程式終止 b = 8 >>> func(3) 3 Traceback (most recent call last): File "<pyshell#6>", line 1, in <module> func(3) File "<pyshell#5>", line 3, in func print(b) UnboundLocalError: local variable 'b' referenced before assignment
如果在函式中賦值時想讓直譯器把 b 當成全域性變數, 要使用 global 語句宣告:
>>> b = 6 >>> def func(a): global b # global語句宣告瞭變數b為全域性變數 print(a) print(b) b = 8 >>> func(3) 3 6
2.2 閉包和自由變數、nonlocal語句
自由變數(free variable),是指未在本地作用域中繫結的變數。如果自由變數繫結的值是可變的,則在閉包中仍然可以操作該變數,如果是不可變的(數字、字串等),則在閉包中重新繫結自由變數會出錯
def make_averager(): count = 0 total = 0 def averager(new_value): count += 1 total += new_value return total / count return averager >>> avg = make_averager() >>> avg(10) Traceback (most recent call last): ... UnboundLocalError: local variable 'count' referenced before assignment
要讓閉包把變數標記為自由變數,可以用nonlocal語句宣告,nonlocal語句解決了上面的問題
def make_averager(): count = 0 total = 0 def averager(new_value): nonlocal count, total # 宣告count、total為自由變數 count += 1 total += new_value return total / count return averager
2.2 變數賦值的一些經驗(for迴圈中)
在下面這個例子中,words = Regex2.sub(replace,words,1) 這一句實際上如同增強賦值,如果將words換為其他名稱,如a或b等都得不到想要的結果,而且,這樣做也省去後面讀寫檔案的一些麻煩
# (檔案讀寫)瘋狂填詞2.py ''' 建立一個瘋狂填詞( Mad Libs)程式,它將讀入文字檔案, 並讓使用者在該文字 檔案中出現 ADJECTIVE、 NOUN、 ADVERB 或 VERB 等單詞的地方, 加上他們自 己的文字。例如,一個文字檔案可能看起來像這樣: The ADJECTIVE panda walked to the NOUN and then VERB. A nearby NOUN was unaffected by these events. 程式將找到這些出現的單詞, 並提示使用者取代它們。 Enter an adjective: silly Enter a noun: chandelier Enter a verb: screamed Enter a noun: pickup truck 以下的文字檔案將被建立: The silly panda walked to the chandelier and then screamed. A nearby pickup truck was unaffected by these events. 結果應該列印到螢幕上, 並儲存為一個新的文字檔案。 ''' import re def mad_libs(filename_path, save_path): with open(filename_path,'r') as strings: # 相對路徑下的文件 words = strings.read() Regex = re.compile(r'\w[A-Z]+') # \w :匹配1個任何字母、數字或下劃線 finds = Regex.findall(words) for i in finds: replace = input('輸入你想替換 {} 的單詞:\n'.format(i)) Regex2 = re.compile(i) words = Regex2.sub(replace,words,1) # 這個變數必須要是words與上面一致否則只列印最後替換的一個,可以畫棧堆圖跟蹤這個變數的值 print(words) # strings.close() 不用這一行,with 上下文管理器會自動關閉 with open(save_path,'a') as txt: txt.write(words + '\n') #分行寫 txt.close() # save_txt = open('儲存瘋狂填詞文件.txt','a') # save_txt.write(words) # save_txt.close() if __name__ == '__main__': filename_path = input('輸入要替換的txt文字路徑:') # '瘋狂填詞原始文件.txt' save_path = input('輸入要儲存的檔案路徑(包含檔名稱):') # '儲存瘋狂填詞文件.txt' mad_libs(filename_path, save_path)
3. 引數
3.1 形參和實參
在def語句中,位於函式名後面的變數通常稱為形參,而呼叫函式時提供的值稱為實參。在函式內部重新關聯引數(即繫結,也就是賦值)時,函式外部的變數不受影響。
>>> def try_to_change(n): ... n = 'Mr. Gumby' ... >>> name = 'Mrs. Entity' >>> try_to_change(name) >>> name 'Mrs. Entity'
4. 棧堆圖
參考自《像電腦科學家一樣思考Python》
# 棧堆圖.py def print_twice ( bruce ): print ( bruce ) print ( bruce ) def cat_twice (part1 , part2 ): cat = part1 + part2 print_twice (cat) line1 = 'Bing tiddle' line2 = 'tiddle bang .' cat_twice (line1 , line2 )
1. 每個函式用一個棧幀 (frame) 表示。一個棧幀就是一個線框,函式名在旁邊,形參以及 函式內部的變數則在裡面。前面例子的堆疊圖如圖 3.1所示。 2. 這些線框排列成棧的形式,說明了哪個函式呼叫了哪個函式等資訊。在此例中,print_twice 被 cat_twice 呼叫,cat_twice 又被 __main__ 呼叫,__main__ 是一個表示最上層棧幀的特殊名 字。當你在所有函式之外建立一個變數時,它就屬於 __main__。 3. 每個形參都指向其對應實參的值。因此,part1 和 line1 的值相同,part2 和 line2 的值相 同,bruce 和 cat 的值相同。 4. 如果函式呼叫時發生錯誤,Python 會列印出錯函式的名字以及呼叫它的函式的名字,以 及呼叫後面這個函式 的名字,一直追溯到 __main__ 為止。 例如,如果你試圖在 print_twice 裡面訪問 cat ,你將獲得一個 NameError : 5. 這個函式列表被稱作回溯 (traceback) 。它告訴你發生錯誤的是哪個程式檔案,錯誤在 哪一行,以及當時在執行哪個函式。它還會顯示引起錯誤的那一行程式碼。 回溯中的函式順序,與堆疊圖中的函式順序一致。出錯時正在執行的那個函式則位於回 溯資訊的底部。 |
3. 函式程式碼實踐(源自《Python程式設計快速上手 讓繁瑣工作自動化》)
''' 編寫一個名為 collatz()的函式,它有一個名為 number 的引數。如果引數是偶數,那麼 collatz()就列印出 number // 2, 並返回該值。 如果 number 是奇數, collatz()就列印並返回 3 * number + 1。 讓使用者輸入一個整數, 並不斷對這個數呼叫 collatz(), 直到函式返回值1 (令人驚奇的是, 這個序列對於任何整數都有效, 利用這個序列,你遲早會得到 1! 既使數學家也不能確定為什麼。 你的程式在研究所謂的“Collatz序列”, 它有時候被稱為“最簡單的、 不可能的數學問題”)。 在前面的專案中新增 try 和 except 語句,檢測使用者是否輸入了一個非整數的字串。正常情況下, int()函式在傳入一個非整數字符串時,會產生 ValueError 誤, 比如 int('puppy')。在 except 子句中,向使用者輸出一條資訊,告訴他們必須輸入一個整數。 ''' def collatz(number): if number == 1: return 1 elif number % 2 == 0: numbers = number // 2 print(numbers) collatz(numbers) elif number % 2 == 1: numbers = 3*number + 1 print(numbers) collatz(numbers) try: number = int(input("請輸入一個整數->:")) collatz(number) except ValueError: print("please input a integer number")