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
關鍵字參數;args
和 kwargs
可以任意命名,慣例是使用 args
和 kwargs
。
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表達式來簡化局部函數。
def foo(bar):
bar()
foo(lambda: print("hello"))
結果如下:
hello
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。