程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python的函數簡介

編輯:Python

環境

  • Ubuntu 22.04
  • Python 3.10.4

函數

空函數

def foo():
pass
foo()

輸出為空。

其中 pass 是占位符。

參數和返回值

def my_max(x, y):
return x if x > y else y
print(my_max(10, 20))

其中 x if x > y else y 是三目運算,類似於Java裡的 x > y ? x : y

結果如下:

20

多個返回值

def my_sum_and_avg(my_list):
s = 0
a = 0
count = len(my_list)
for e in my_list:
s += e
a = s / count
return s, a
list1 = [10, 20, 30, 100]
result = my_sum_and_avg(list1)
print(result)
s1, a1 = my_sum_and_avg(list1)
print(s1, a1)

結果如下:

(160, 40.0)
160 40.0
  • 第一次調用函數時,用一個變量接收多個返回值,會自動封裝為元組;
  • 第二次調用函數時,用多個變量接收多個返回值;

通過關鍵字指定參數

前面在調用函數時,是通過位置來指定參數,此外也可以通過關鍵字(形參名字)來指定參數:

def foo(width, height, age):
print("width = ", width, "height = ", height, "age = ", age)
foo(100, 200, 20)
foo(height=100, age=30, width=200)
foo(100, age=20, height=150)

結果如下:

width = 100 height = 200 age = 20
width = 200 height = 100 age = 30
width = 100 height = 150 age = 20
  • 第一次調用函數時,通過位置指定參數;
  • 第二次調用函數時,通過關鍵字指定參數;
  • 第三次調用函數時,位置和關鍵字混合使用;

注意:位置和關鍵字混合使用時,關鍵字參數必須在位置參數之後。

下面的用法會報錯:

foo(100, width=200, age=20)

因為第一個參數是位置參數,一定會綁定到 width 參數,如果後面再次指定 width 參數,會報錯: TypeError: foo() got multiple values for argument 'width'

參數默認值

在定義函數時,可以給參數指定默認值。

注意:帶默認值的參數必須在沒有默認值的參數之後。

def foo(age, width=10, height=20):
print("age = ", age, "width = ", width, "height = ", height)
foo(20, 100, 200)
foo(20)
foo(20, 100)

結果如下:

age = 20 width = 100 height = 200
age = 20 width = 10 height = 20
age = 20 width = 100 height = 20
  • 第一次調用函數時,指定了三個參數;
  • 第二次調用函數時,指定了一個參數,剩余兩個參數使用默認值;
  • 第三次調用函數時,指定了兩個參數,最後一個參數使用默認值;

個數可變的參數

  • *args :位置參數;
  • **kwargs 關鍵字參數;

argskwargs 可以任意命名,慣例是使用 argskwargs

def foo(*args, **kwargs):
print("args: ", args)
print("kwargs: ", kwargs)
print()
foo(1, 2, 3)
foo(a=1, b=2, c=3)
foo(1, 2, 3, a=4, b=5, c=6)

結果如下:

args: (1, 2, 3)
kwargs: {
}
args: ()
kwargs: {
'a': 1, 'b': 2, 'c': 3}
args: (1, 2, 3)
kwargs: {
'a': 4, 'b': 5, 'c': 6}

逆向參數收集

若函數需要多個參數,而調用函數時,只傳一個參數(如列表,元組,字典),則會自動拆開。

  • 列表,元組:添加 *
  • 字典:添加 **
def foo(width, height):
print("width = ", width, "height = ", height)
list1 = [100, 200]
foo(*list1)
tuple1 = (10, 20)
foo(*tuple1)
dict1 = {
"height": 1, "width": 2}
foo(**dict1)
dict2 = dict(height=1, width=2)
foo(**dict2)

結果如下:

width = 100 height = 200
width = 10 height = 20
width = 2 height = 1
width = 2 height = 1

變量作用域

name = "Tom"
def foo():
age = 20
print(name, age)
foo()
print(name)

結果如下:

Tom 20
Tom

沒有問題,在函數內部可以訪問全局變量。

但是如果(在訪問全局變量之後)試圖修改其值,會報錯:

name = "Tom"
def foo():
print(name)
name = "Jerry"
foo()

報錯如下:

UnboundLocalError: local variable 'name' referenced before assignment

這是因為在函數內部的 name = "Jerry" 會產生一個新的局部變量。

同理,如果在函數內部只給 name 賦值:

name = "Tom"
def foo():
name = "Jerry"
print("before:", name)
foo()
print("after:", name)

結果如下:

before: Tom
after: Tom

在函數內修改 name, 並不影響全局變量,這是因為函數裡的 name 是一個新的局部變量,並不是那個全局的 name

若要修改/修改全局變量,有兩種方法:

  • 添加 global <變量名> 聲明:
name = "Tom"
def foo():
global name
name = "Jerry"
print("before:", name)
foo()
print("after:", name)

結果如下:

before: Tom
after: Jerry
  • 通過 global() 函數訪問:
name = "Tom"
def bar():
print(globals()['name']) # 顯式使用全局變量name
name = "Jerry" # 該name是局部變量
print("before:", name)
bar()
print("before:", name)

結果如下:

before: Tom
Tom
before: Tom

局部函數

前面的函數都是在全局范圍內定義的,叫做全局函數,而在函數內定義的函數叫做局部函數。

默認情況下,局部函數對外不可見,只在其封閉(enclosing)函數內有效:

def foo():
def bar():
print("hello")
bar()
foo()

結果如下:

hello

foo() 函數之外是不能直接訪問 bar() 函數的。

如果局部函數需要訪問其上級(全局函數)定義的變量,也有前面提到的作用域問題,需要先用 nonlocal 聲明一下:

def foo():
name = "Tom"
def bar():
nonlocal name
print(name)
name = "Jerry"
bar()
print(name)
foo()

結果如下:

Tom
Jerry

注意:如果沒有 nonlocal name ,程序會報錯 UnboundLocalError: local variable 'name' referenced before assignment

函數變量

函數本身也可以當做變量來使用。注意函數當變量時,後面不要加括號,否則就變成函數調用了。

def foo():
print("hello")
bar = foo
bar()

結果如下:

hello

同理,函數也可以當作參數或者返回值。

  • 函數作為參數:
def my_fun():
print("hello")
def foo(bar):
bar()
foo(my_fun)

結果如下:

hello
  • 函數作為返回值:
def foo():
def my_fun():
print("hello")
return my_fun
foo()()

結果如下:

hello

foo()() 也可以寫成如下形式:

bar = foo()
bar()

lamda表達式

可以用lamda表達式來簡化局部函數。

  • lamda表達式作為參數:
def foo(bar):
bar()
foo(lambda: print("hello"))

結果如下:

hello
  • lamda表達式作為返回值:
def foo():
return lambda: print("hello")
foo()()

結果如下:

hello

@函數裝飾器

函數作為參數和返回值:

def foo(fn):
def bar(*args, **kwargs):
print(fn.__name__, "before")
fn(*args, **kwargs)
print(fn.__name__, "after")
return bar
def myfunc1():
print("hahaha")
def myfunc2(a, b, c):
print("good")
print(a, b, c)
foo(myfunc1)()
foo(myfunc2)("aa", c="bb", b="cc")

結果如下:

myfunc1 before
hahaha
myfunc1 after
myfunc2 before
good
aa cc bb
myfunc2 after

上面的寫法,可用 @<函數名 的方式來簡化:

def foo(fn):
def bar(*args, **kwargs):
print(fn.__name__, "before")
fn(*args, **kwargs)
print(fn.__name__, "after")
return bar
@foo
def myfunc1():
print("hahaha")
@foo
def myfunc2(a, b, c):
print("good")
print(a, b, c)
myfunc1()
myfunc2("aa", c="bb", b="cc")

當使用 @foo 修飾 myfunc1 的函數定義時,相當於 foo(myfunc1) 。同時將 myfunc1 替換為 foo(myfunc1) 的返回值,本例中也就是 bar 函數。

這有點類似於Spring裡面的AOP。


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved