10 函數 Function
##1 函數的定義 使用關鍵字`def = define`來進行定義 定義函數的目的: 1.最大化代碼重用,dry原則(don't repeat yourself) 2.最小化代碼冗余 3.過程分解 函數的定義:`def 函數名稱(形參):`2 函數的調用
函數名稱(實參)
def learning(name, course, start, end):
print('{} is learning {}'.format(name, course))
print('{} to {}'.format(start, end))
learning('Jerry', 'python入門經典', '2018/7', '2018/9')
3 函數的返回值
使用return來返回函數的值,python具有多態的特性,而可以實現不同類型的計算,然后返回。
def add_num(x, y): return (x + y)
print(add_num(3, 5))
例子,找出兩個序列中的重復部分:
這個例子可以實現多態的特性,實參只要是序列就可以了,可以是list也可以str類型
def intersect(seq1, seq2):
res = []
for x in seq1:
if x in seq2:
res.append(x)
return res
seqA = [1, 5, 65, 8, 4, 5, 4]
seqB = [1., 2, 45, 1, 65, 4]
print(intersect(seqA, seqB))
結果:[1, 65, 4, 4]
同樣也可以通過集合set來實現得出兩個不同的元素
seqA = [1, 5, 65, 8, 4, 5, 4]
seqB = [1, 2, 45, 1, 65, 4]
s1 = set(seqA) & set(seqB)
print(s1)
結果:{65, 4, 1}
4 函數的作用域
4.1 函數內的變量的作用域
1.函數里面定義的變量成為local,作用域為函數內部。
2.函數外部定義的是global全局的變量
3.另外的是built-in內置的類型,其作用域最高
# 函數內的變量的值和外部變量重復了
# 函數內的變量的作用域的問題
x = 50
def fun():
x = 99
return x
print('函數運行后的x的值是{}'.format(fun()))
print('全局的x的值是{}'.format(x))
結果:
函數運行后的x的值是99
全局的x的值是50
4.2 在函數的內部使用global關鍵字的變量
可以在函數中使用global關鍵字來聲明該變量為全局的變量
# 函數內的變量的值和外部變量重復了
# 函數內的變量的作用域的問題
x = 50
def fun():
global x
x = 99
return x
print('函數運行后的x的值是{}'.format(fun()))
print('全局的x的值是{}'.format(x))
結果:
函數運行后的x的值是99
全局的x的值是99
4.3 python3中的封裝enclosure
使用場景為函數中又嵌套了函數,嵌套的函數變量和上一層的函數的變量名稱相同,可以使用nonlocal關鍵字。
優先級的順序:LEGB

4.3.1 函數中嵌套函數的作用域
從下面的例子可以看出函數變量的作用域,其中enclosure的優先級是最低的,其次是local,然后是global,最后是built-in
x = 10
def f1():
x = 99
def f2():
x = 100
print(x)
print(x) # 打印的是f1 local的x
f2() # 打印的是f2 local的x
print(x) # 打印的是f1 local的x
f1()
print(x)
結果:
99 # 打印的是f1的
100 # 打印的是f2的
99 # 打印的是f1的
10 # 打印的是global的
如果要在嵌套的函數中使用全局的,就使用global的關鍵字,如果只是想使用外側的,就使用nonlocal的關鍵字來實現。
x = 10
def f1():
x = 99
def f2():
nonlocal x
x = 100
print(x)
print(x) # 打印的是f1 local的x
f2() # 打印的是f2 local的x
print(x) # 打印的是f1 local的x
f1()
print(x)
結果:
99
100
100
10
4.3.2 Built-in
如果定義了一個方法,將built-in覆蓋了,就會使用定義的函數,編寫的時候特別注意,不要覆蓋了built-in的函數。
5 函數的參數傳遞
變量類型,大致可以分為2種,一種是可變類型,另外一種是不可變類型。
5.1 傳遞實參是不可變類型
不可改變的類型,如int類型,作為參數傳遞到函數,此時是作為副本傳遞,實參的值是不會改變的。
例子1,傳遞的是一個int類型
def change_num(x):
x += 10
x = 5
change_num(x)
print(x)
結果:
5
例子2,傳遞的是一個str類型
def change_num(x):
x += 'abc'
x = 'Hellokitty'
change_num(x)
print(x)
結果:Hellokitty
5.2傳遞實參是可變類型
可改變類型作為實參,傳遞給函數,函數進行的操作,會改變可變類型的本身的值,如下的list的類型。
def change_num(x):
x[0] = '99'
x = [1,2,3]
change_num(x)
print(x)
結果:['99', 2, 3]
如果我想傳遞一個list但是又不想改變,可以手動傳遞副本,而不是直接傳遞值,這里本質上淺拷貝,如果有列表嵌套也不會奏效。
def change_num(x):
x[0] = '99'
x = [1, 2, 3]
change_num(x[:])
print(x)
5.3傳遞可變和不可變實參的原理
傳遞可變類型,實際是傳遞的一個值,而不可變的類型傳遞的是一個引用。

6 函數的參數的匹配
6.1傳遞安裝順序傳遞,位置匹配
默認情況下是安裝位置的順序進行匹配的
def func(a, b, c):
print(a, b, c)
func(1, 2, 3)
func('a', 'b', 'c')
6.2傳遞參數,按照變量的值匹配
也可以通過指定參數的值來進行參數的傳遞
def func(a, b, c):
print(a, b, c)
func(1, 2, 3)
func('a', 'b', 'c')
func(c=15, a=16, b=55)
6.3默認值傳遞值
在定義函數的時候,就可以將參數賦予默認值,在傳遞實參的時候可以傳遞部分值給形參。
但是要注意一點:定義函數的默認值只能放在最后面
def func(a, b=1, c=1):
print(a, b, c)
func(18)
func(1,15)
結果:
18 1 1
1 15 1
6.4函數接收多個不確定個數的參數*arg
python是一個動態類型,可以傳遞事先不確定個數的任意參數。
沒有函數的重載,但是python設計可以在聲明函數時,表明可以接收任意個數的參數,其中會將多余的參數以tuple的形式傳遞給arg
6.4.1python在定義函數的時候,在形參的前面加上*來表明可以接收可變個數的參數:
def avg(*score):
return sum(score) / len(score)
print(avg(99, 100, 87, 75, 62))
print(avg(87, 99, 85, 68))
6.4.2 聲明了接收可變參數,但傳遞的是一個元組,需解包
如果函數定義可以接收可變參數,但是將參數已經全部保存在一個tuple里面了,此時如果要傳遞這個tuple,需要先進行解包的操作。
# 如下會報錯
def avg(*score):
return sum(score) / len(score)
t = (87., 94, 98, 78)
avg(t)
結果:
Traceback (most recent call last):
File "D:/str_2_unicode/str_2_unicode.py", line 7, in <module>
avg(t)
File "D:/str_2_unicode/str_2_unicode.py", line 2, in avg
return sum(score) / len(score)
TypeError: unsupported operand type(s) for +: 'int' and 'tuple'
正確的操作如下,需要先進行解包的操作
def avg(*score):
return sum(score) / len(score)
t = (87., 94, 98, 78)
print(avg(*t))
結果:89.25
如下例子,將他直接進行傳遞,可以看到t作為一個參數被傳遞了,而并未被解開
def func(*args):
print(args)
t =(1,2,3)
func(t)
func(*t)
結果:
((1, 2, 3),)
(1, 2, 3)

6.4.3 函數實參為字典表
可以在定義函數的時候使用**,將多余的參數以dict的方式來呈現。
例如,如果要處理一個員工的信息,包括 name,age,job,salary,當然可以使用4個形式參數,然后傳遞4個實際的參數到函數進行處理,如下:
def staff_info(name, age, job, salary):
print(name, age, job, salary)
staff_info('Jerry',20,'dev',9000.00)
結果:Jerry 20 dev 9000.0
但是有的時候,也不太確定要傳遞參數的個數,并且這些參數明顯是具有相關性的,可以通過傳遞字典表來解決這個問題。
def func(**arg),使用**來表示將傳遞的多余部分以字典表方式處理
擴展閱讀
http://www.rzrgm.cn/xuyuanyuan123/p/6674645.html
要注意的是,傳遞的是一個鍵值對,其中鍵的值并不需要加上引號。
def staff_info(**kwargs):
print(kwargs)
staff_info(name='Lucy', age=20, job='dev', salary=11000)
結果:{'salary': 11000, 'age': 20, 'job': 'dev', 'name': 'Lucy'}
如果要傳遞的參數本身就已經是一個dict類型,需要進行解包操作。
def staff_info(**kwargs):
print(kwargs)
lucy_info = dict(name='Lucy', age=20, job='dev', salary=11000)
staff_info(**lucy_info)
如果不進行解包操作,則會報錯:
def staff_info(**kwargs):
print(kwargs)
lucy_info = dict(name='Lucy', age=20, job='dev', salary=11000)
staff_info(lucy_info)
Traceback (most recent call last):
File "D:/str_2_unicode/str_2_unicode.py", line 7, in <module>
staff_info(lucy_info)
TypeError: staff_info() takes 0 positional arguments but 1 was given
浙公網安備 33010602011771號