1. 程式人生 > >Cris 的Python筆記(六):函式基礎

Cris 的Python筆記(六):函式基礎

1. 函式基礎語法知識

# 函式:函式也是一個物件,用來儲存可執行的程式碼並且在需要時隨時呼叫;而物件就是記憶體中用來儲存資料的一片記憶體空間

# 建立函式:def 函式名([arg1,arg2...]):
#               程式碼塊


def func():
    print('hello,cris')
    print('i am function of python')


# 呼叫函式
func()
print(type(func))   # <class 'function'>

# 函式的形參:定義形參相當於在函式內部定義了變數,但是並沒有賦值
# 函式的實參:如果函式定義了實參,那麼呼叫該函式時就需要傳遞對應的實參
def func(a, b): return a + b result = func(1, 2) print(result) # 3 # 函式引數詳解:1. 可以為函式的形參指定預設值,如果使用者傳遞了引數,則預設值失效;如果使用者沒有傳遞實參,那麼預設值生效 # 2.實參的傳遞方式:位置;關鍵字 def func(a, b, c=10): print(a, b, c) # 位置傳參 func(1, 2, 3) # 1 2 3 # 關鍵字傳參 func(c=11, a=12, b=0) # 12 0 11 # 位置傳參和關鍵字傳參可以混合使用,但是位置引數必須寫在關鍵字引數前面,否則無法區分
# func(b=12,23,11) # 報錯 # 函式呼叫時,無法對實參進行型別檢查(Python 是一種動態語言);所以實參可以傳遞任意資料型別 func(func, 22) # <function func at 0x000001836D1057B8> 22 10 # Python 中的值傳遞:實參如果指向的是可變資料型別的物件,那麼函式中形參修改物件將會影響到所有指向這個物件的變數; # 實參如果指向的是不可變資料型別,那麼形參的修改將不會對實參產生任何影響(換句話說,Python和java 類似,引數傳遞都是值傳遞型別) def func(a): a = 'cris'
print(a) b = 'james' func(b) print(b) # 不定長函式:定義引數時,可以在一個形參前面加上*,這個形參就會獲取到所有的實參,並且以元祖的形式展現,也稱之為引數的裝包 # 帶* 號的引數只能寫一個,並且可以和其他形參聯合使用:例如(a,b,*c) # 如果帶* 號的形參寫在中間,那麼帶* 號的形參後面的所有引數都必須以關鍵字的形式傳遞引數 # 如果在形參列表的開頭寫一個*,那麼表示該函式的實參都必須以關鍵字的形式來傳參:(*,a,b,c) def sum(a, *b): print(a, b, type(b)) sum(1, 2, 3) # 1 (2, 3) <class 'tuple'> def sum(*nums): result = 0 for i in nums: result += i print(result) sum(1, 2, 3, 4) # 10 # *號形參只能接受位置引數 def func(*a): print(a) func(1, 2, 3) # (1, 2, 3) # func(b=2, c=3) # 報錯 # 如果使用**號形參可以接受任意個關鍵字傳參,預設會將這些引數統一儲存到字典中,字典的key 就是引數的名字,value就是引數的值。**號形參只能寫一個,並且必須寫在最後一個 def func(**a): print(a) func(b=1, c=2) # {'b': 1, 'c': 2} # 引數的解包:傳遞實參時,可以在序列型別的引數前面加上*,這樣就會自動將序列中的元素依次作為引數傳遞 def func(a, b, c): print(a, b, c) args = (1, 2, 3) func(*args) # 1 2 3 # 兩個** 可以對字典解包,前提是引數名和key名需要一一對應 args = {'a': 100, 'b': 200, 'c': 300} func(**args) # 100 200 300 # 函式的返回值: return 關鍵字可以返回任意資料型別的物件(甚至函式),可以直接使用函式的返回值,或者使用變數來接收; # return後面不加值或者不寫return,則相當於return None;return 還可以用於結束函式 # break,continue,return 之間的區別 # fn 和 fn()的區別:一個是函式物件,一個是呼叫函式的結果 def sum(*nums): result = 0 for i in nums: result += i return result result = sum(1, 2, 3) print(result) # 6 # return 後面接函式物件的特殊情況(JAVA 無法這樣) def fn1(): def fn2(): print('this is fn2') return fn2 f = fn1() f() # this is fn2

2. 文件字串(Python中的函式規範)

# 文件字串:doc string,用於定義函式的說明
# help()是Python的內建函式,可以用於查詢Python中函式的用法(但是可以使用外掛自動提示~)
# help(print)

# 直接在函式的第一行使用```xxx```來書寫函式說明

# 如果要寫的更加規範和講究,可以參考下面的Python 寫法:
# 1. 在每個引數的後面使用:資料型別 來為函式的形參做出型別要求(但是無法進行強制檢查,僅僅提示)
# 2. 然後在函式宣告的末尾使用 -> 資料型別 來對該函式的返回值做出型別提示


def func1(a: int, b: bool, c: str='cris') -> str:
    '''
        函式的作用:
        引數a:
        引數b:
        引數c:
        返回值:
    '''
    print(a, b, c)  # 1 True cris
    return str(a) + str(b) + c


help(func1)  # 檢視函式的說明
print(func1(1, True))    # 1Truecris

3. 函式的作用域和名稱空間

# 函式變數的作用域(scope):在Python 中,變數一共有兩種作用域:一種是全域性作用域;一種是函式作用域
# 全域性作用域:
# - 在程式執行的時候建立,程式執行結束後銷燬
# - 所有函式以外的區域都是全域性作用域
# - 在全域性作用域中定義的變數,都屬於全域性變數,全域性變數可以在程式的任意位置被訪問

# 函式作用域:
# - 函式作用域在函式被呼叫時建立,呼叫結束後被銷燬
# - 函式沒呼叫一次,就會建立一個新的函式作用域
# - 在函式作用域中定義的變數,就是區域性變數,只能在函式內部被訪問

a = 10


def fn():
    print(a)


fn()    # 10

# 作用域支援就近原則以及層級巢狀(由內往外)


def fn1():
    a = 11

    def fn2():
        a = 12
        print("a:", a)
    fn2()


fn1()   # a:12

# 如果想要在函式內部修改全域性作用域的變數,需要使用 global 關鍵字


def fn3():
    # 宣告全域性作用域的變數
    global a
    a = 'cris'  # 對全域性作用域的變數進行修改
    print('cris=', a)


fn3()   # cris= cris
print('a=', a)  # a= cris

# 命令空間(namespace):命令空間指的就是變數儲存的位置,每一個變數都需要儲存到對應的名稱空間中去
# 即每一個作用域都有其對應的名稱空間:全域性作用域對應的全域性名稱空間用來儲存全域性變數;函式作用域對應的區域性名稱空間用來儲存區域性變數
# 名稱空間實質上就是一個字典,宣告的變數都是以key-value 的形式儲存到這個字典中

# locals()函式用於獲取名稱空間,在全域性作用域呼叫獲取的是全域性名稱空間;在函式作用域呼叫,獲取的是函式的名稱空間
space = locals()
print(type(space))  # <class 'dict'>
print(space['a'])   # cris

# 宣告變數其實就是在往名稱空間新增鍵值對
space['b'] = 123
# print(b)    # 123,不推薦使用這種方式定義變數,瞭解即可

# 可以通過global()在任意位置獲取全域性名稱空間,不建議使用