Python/函數

維基教科書,自由的教學讀本
跳至導覽 跳至搜尋

函數定義[編輯]

Python函數定義的通常格式為:

def 函数名参数列表:
    #函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明
    函数体
    #return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None

參數的傳值與傳引用[編輯]

Python中,對象有類型;變量僅僅是對象的一個引用,變量沒有類型。 string、tuple和 numbers 是不可更改的類型(immutable type),給它們的變量賦值其實是指向了新的對象;而 list,dict 等則是可以修改的類型(mutable type)。Python函數的參數傳遞

  • 不可變類型:類似 C語言的值傳遞。在函數內部「修改」參數的值,只是引用到另一個對象,不影響實參本身。
  • 可變類型:類似C++的引用傳遞,修改後函數外部的實參也會受影響

命名實參與不定長參數[編輯]

Python的函數實參可分為兩類:(無命名的)位置實參、命名實參。

  • 函數調用時,首先匹配所有位置參數,即使關鍵字參數更靠左也會稍後才處理。額外的未匹配的位置參數組成一個元組與*args形參匹配。
  • 一個星號*為前綴的形參名字,對應於匹配了位置形參與命名形參後剩下的額外位置參數,組成的一個元組。
    • 單獨一個星號沒有形參名字,只是一個分隔符,並不對應於實參,而是表示實參表此處向右都必須是命名參數。出現在*args或者**kwargs之後的形參都是命名參數。
  • 兩個星號*為前綴的形參名字,對應於額外的命名實參組成的一個字典。
  • 帶預設值的參數,其右側直至*的參數都必須有預設值。參數的預設值在函數定義時從左至右求值。

通常,不在一個函數同時使用*args與**kwargs,以免混淆。

函數調用時,如何傳入任意多的實參? 使用「逆向參數收集」。即在list變量名字前面加上*號作為實參;tuple變量名字前面加上**號作為實參。

def test1(a, b, c=0, *args, **kwargs):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kwargs)
 
def test2(a, b, c=0, *args, d, **kwargs):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'args=', args, 'kw =', kwargs)
 
# 定义一个元组和字典用作参数传入
args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
 
test1(*args, **kw)
# a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
test2(*args, **kw)
#a = 1 b = 2 c = 3 d = 99 args= (4,) kw = {'x': '#'}

def test3(a, *args,d, c=0):
    print('a =', a, 'c =', c, 'd =', d, 'args=', args)
args=(1,3,5)
test3(-1, d=101, *args)
#输出为:a = -1 c = 0 d = 101 args= (1, 3, 5)

函數返回多個值[編輯]

返回多個值時自動作為一個tuple。函數調用者可以使用多個變量來接受多個返回值(即tuple中的各個成分)。

嵌套函數[編輯]

嵌套函數(nested function),需要注意:

  • 內部函數可以讀寫訪問外部函數的可變(mutable)變量
  • 內部函數可以訪問外部函數的不可變(immutable)變量
  • 內部函數使用nonlocal關鍵字,可以讀寫訪問直接外部函數的不可變(immutable)變量
  • 內部函數訪問的外部函數的變量,可以定義在內部函數之後。

函數閉包[編輯]

閉包是指嵌套函數作為外部函數的返回值。因為函數是頭等對象,所以函數對象可以作為實參、返回值。嵌套函數可以使用外部函數的變量,即使外部函數已經運行結束了。例如

 def adder(outer_argument): # outer function
   def adder_inner(inner_argument): # inner function, nested function
     return outer_argument + inner_argument # Notice outer_argument
   return adder_inner
 add5 = adder(5) # a function that adds 5 to its argument
 add7 = adder(7) # a function that adds 7 to its argument
 print add5(3) # prints 8
 print add7(3) # prints 10

匿名函數[編輯]

匿名函數的語法如下:

 lambda 可选的形参表:expression

lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。lambda 函數擁有自己的命名空間,且不能訪問自己參數列表之外或全局命名空間裡的參數。

偏函數[編輯]

對一個函數的部分參數綁定值後,得到的函數為偏函數:

偏函数名 = partial(func, *args, **kwargs)

其中,func 指的是要封裝的原函數,*args 和 **kwargs 分別用於接收非命名實參和命名實參。

from functools import partial

#定义个原函数
def display(name,age):
    print("name:",name,"age:",age)

#定义偏函数,其封装了 display() 函数,并为 name 参数设置了默认参数
GaryFun = partial(display,name = 'Gary')
#由于 name 参数已经有默认值,因此调用偏函数时,可以不指定
GaryFun(age = 13) #必须以命名实参方式传入,否则会报错:TypeError: display() got multiple values for argument 'name'

def mod( n, m ):
    return n % m

#定义偏函数,并设置参数 n 对应的实参值为 100
mod_by_100 = partial( mod, 100 )
print(mod( 100, 7 ))
print(mod_by_100( 7 ))

eval()與exec()[編輯]

eval(source, globals=None, locals=None, /)
exec(source, globals=None, locals=None, /)

expression參數是一個字符串,代表要執行的語句 。該語句受後面兩個字典類型參數 globals 和 locals 的限制,只有在 globals 字典和 locals 字典作用域內的函數和變量才能被執行。

globals參數管控的是一個全局的命名空間,即 expression 可以使用全局命名空間中的函數。如果只是提供了 globals 參數,而沒有提供自定義的 __builtins__,則系統會將當前環境中的 __builtins__ 複製到自己提供的 globals 中,然後才會進行計算;如果連 globals 這個參數都沒有被提供,則使用 Python 的全局命名空間。

locals參數管控的是一個局部的命名空間,和 globals 類似,當它和 globals 中有重複或衝突時,以 locals 的為準。如果 locals 沒有被提供,則默認為 globals。

eval() 執行完會返回結果,而 exec() 執行完不返回結果

map()、filter()、reduce()[編輯]

由於 map() 函數是直接由用 C 語言寫的,運行時不需要通過 Python 解釋器間接調用,並且內部做了諸多優化,所以相比其他方法,此方法的運行效率最高。

reduce() 函數在 Python 3.x 中已經被移除,放入了 functools 模塊,因此在使用該函數之前,需先導入 functools 模塊。

函數註解[編輯]

「函數註解是關於用戶自定義函數使用類型的可選的元信息」。也就是說,函數註解的用途為「函數中的形參和返回值提供類型提示信息」。注意,函數註解沒有任何語法上的意義,只是為函數參數和返回值做註解,並在運行獲取這些註解,僅此而已。換句話說,為函數做的註解,Python不做檢查,不做強制,不做驗證,什麼操作都不做,函數註解對Python解釋器沒任何意義。

    def f(ham:str,egg:str='eggs')->str:
      pass
    print(f.__annotations__)

#输出结果为:{'ham': <class 'str'>, 'egg': <class 'str'>, 'return': <class 'str'>}