Python:函式解釋(程式導向)

thoustree發表於2021-04-20

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")

 

相關文章