1. 程式人生 > 實用技巧 >Python-2 函式、引數

Python-2 函式、引數

函式

  1. help(abs):檢視函式 abs 的幫助資訊
  2. pass:佔位符,還沒想好怎麼寫,先 pass,讓程式跑起來看一下。
    • 比如在 if 語句下,定義函式如下。
    def my_abs(x):
        if not isinstance(x, (int, float)):
            raise TypeError('bad operand type')
        if x >= 0:
            return x
        else:
            return -x
    
  3. 定義函式下,第一行使用:"函式的說明註釋"
  4. Python 可以返回多個值,return x, y
  5. 接收:x, y = test(xxx)
  • 返回的其實是一個元組,多個變數接收一個元組,則元組將元素按順序賦值給變數
  1. isinstance(x, (int, float))x 是否為 int 或 float 型別
    reise TypeError('錯誤提示文字')丟擲型別錯誤
  2. 不同於 java ,Python 可以有預設引數,可寫成 def power(x, n=2),此時呼叫 power(5),相當於 power(5, 2)
  3. 預設引數為可變型別的陷阱

有一函式 drf x(L[]):多次呼叫 x()(不傳引數,使用預設引數),則會發現這個預設引數被存下來了。

def add_end(L=[]):
    L.append('END')
return L
>>> add_end()
['END']

>>> add_end()
['END', 'END']

>>> add_end()
['END', 'END', 'END']
  • def 中,預設引數被定義了,擁有了一個記憶體地址。直接呼叫預設引數的話(沒給引數),會對該地址進行操作,導致該預設引數被改變了。

所以應該儘量使預設引數為不可變引數。

def add_end(L=None):
    if L is None:
        L = []
        L.append('END')
return L
  • 這裡,def
    中的引數是固定的,在函式中每次都新建了一個列表,再多次呼叫預設引數函式,大家各自安好。
  1. 函式的不加任何東西的引數預設是位置引數(必須引數),不可缺少。
  2. 可批量代入引數:將一個元組/列表,使用 * 當做引數的合體傳入函式:
def computed(x, y):
    print(x, y)

x = [1, 1] # 或者:x = (1, 1)
computed(*x)
  1. 函式內可以再定義函式,並且這個內部函式可以訪問外部函式的引數和區域性變數。

可變引數

定義可變引數的函式(java 裡的 ...):

def calc(*numbers)
  • 可變引數 numbers 在函式裡被合併為一個元組,在外面呼叫函式直接傳進來多個值即可。
  • 呼叫函式時,也可以使用:calc(*tuple1),直接將一個元組/列表作為引數。
def computed(x, y, *z):
    print("可變引數:", z)
    print(x, y)

x = [1, 1, 2, 2]
computed(*x, **n)

可變引數: (2, 2)
1 1

關鍵字引數

關鍵字引數 **kw 相當於可變引數 *args 的變種,也是一種可選的,但是它是鍵值對形式。

def person(name, age, **kw):
  1. kw字典,鍵值對;nameage 稱為位置引數
  2. nameage 是必要的,而關鍵字引數是次要的,擴充套件的。
  3. 呼叫:person('Bob', 18, city='Xiamen', job='ceo')必須傳入引數名,否則會被識別為位置引數,出現錯誤。
  4. 同樣,呼叫函式時使用 person('Bob', 18, **extra),將一個名為 extra 的字典做為引數傳入。
  • 值得注意的是,這裡的 **extra 只是 extra 的一個淺拷貝,函式內的對不可變元素的操作不會影響外部的 extra,但操作可變元素有影響。

在呼叫函式時,使用如:x(age=12),可以僅傳入一個年齡的引數,不會是 name 的值。

命名關鍵字引數:限制關鍵字引數的名字

def person(name, age, *, city='Beijing', job): # 在星號後面寫上關鍵字引數應有的鍵名

這裡除必須引數外,還限制必須要有且僅有名為 cityjob 的引數傳進來。

  • 如果有可變引數,可變引數後面的關鍵字引數可以不再用 * 分隔了,後面預設是關鍵字引數:def person(name, age, *args, city, job)
  • 如果關鍵字引數有預設值,則可以不用必須傳入
    • 比如這樣可以呼叫上面小標題下的函式:person('Jack', 24, job='Engineer')

強制位置引數

在上面的引數中的,呼叫時:

  • f(10) 使用的是位置引數,沒有,是沒有帶名字的引數
  • f(a = 10) 使用的是關鍵字引數/命名關鍵字引數,帶有名字

Python 3.8 新增了一種引數 /,使得前面的引數呼叫必須使用位置引數:

def f(a, b, /, c, d, *, e, f)
  print(a, b, c, d, e, f)

以下使用方法是正確的:

f(10,  20,  30, d=40, e=50, f=60)

以下使用方法會發生錯誤:

f(10, b=20, c=30, d=40, e=50, f=60)  # b 不能使用關鍵字引數的形式
f(10, 20, 30, 40, 50, f=60)  # e 必須使用關鍵字引數的形式

引數組合

有多種引數的話,按照邏輯以及要求,必須按順序來:必選引數(位置引數)、預設引數、可變引數、命名關鍵字引數和關鍵字引數。

def f2(a, b, c=0, *, d, **kw)
#      必 必  默    命名  關鍵
# f2函式要有a,b,可選c引數,還必須要有d=value
# 因為有**kw,所以還可有其他帶名字的鍵值對傳入

對於任意函式,都可以通過類似 func(*args, **kw) 的形式呼叫它,無論它的引數是如何定義的。

  • *args 囊括必選引數、預設引數、可變引數
  • **kw 囊括命名關鍵字引數、關鍵字引數

遞迴函式

解決遞迴呼叫棧溢位的方法:尾遞迴
大多數程式語言沒有針對尾遞迴做優化,Python直譯器也沒有做優化,所以,即使把階乘的 fact(n) 自定義函式改成尾遞迴方式,也會導致棧溢位。

匿名函式

lambda 表示式,它是一個表示式,只包含一個語句,而不是一個程式碼塊。僅僅能在lambda表示式中封裝有限的邏輯進去。

lambda  [arg1 [,arg2,.....argn]]:expression
# 冒號前引數,冒號後表示式

示例:

sum = lambda arg1, arg2: arg1 + arg2
# 呼叫sum函式
print("相加後的值為: ", sum(10, 20))
print("相加後的值為: ", sum(20, 20))