函數
數學定義:y=f(x),y是x的函數,x是自變量
Python函數
有若干個語句塊,函數名稱,參數列表構成,它是組織代碼的最小單元
完成一定作用
函數的作用
結構化編程對代碼的最基本的封裝,一般按照功能組織一段代碼
封裝的目的為了復用,減少了冗余代碼
代碼更加簡潔美觀,更加易讀
函數的分類
內建函數,如max(),reversed()等
庫函數,如math.ceil()等
函數的調用
def語句定義函數
def函數名(參數列表):
函數體(代碼塊)
[return 返回值]
函數名就是標識符,命名標準一樣
語句塊必須要縮進,約定4個空格
Python的函數沒有return語句,隱式會返回一個None值
定義中的參數列表成為形式參數,只是一種符號表達,簡稱形參
調用
函數的定義,只是聲明了一個函數,他不會被執行,需要調用
調用的方式,就是函數名加上小括號,括號內寫上參數
調用的時候寫的參數是實際參數,是實實在在傳入的值,簡稱實參
函數舉例:
def add(x,y):
????result=x+y
????return result
out = add(4,5)
print(out)
上面只是一個函數的定義,有一個函數叫做add,接收2個參數
計算的結果,通過返回值返回
調用的通過函數名add加2個參數,返回值可使用變量接受
定義需要在調用前,也就是說調用時,已經被定義過了,否者Nameerror異常
函數參數
參數調用時傳入的參數要和定義的個數匹配(可變參數例外)
位置參數
def f(x,y,z)調用使用f(1,3,5)
按照定義順序傳入實參
關鍵字參數
def f(x,y,z)調用使用f(x=1,y=3,z=5)
使用形參的名字來出入實參的方式,如果使用了形參名字,那么順序可以改變
傳參
f(z=None,y=10,x=[1])
f((1),z=6,y=4.1)
要求位置參數必須在關鍵字參數之前傳入,位置參數是按照位置對應的
函數參數默認值
參數默認值:定義時,在形參后跟上一個值
def ad(x=4,y=5):
return x+y
測試調用add(6,10),add(6,y=7),add(x=5),add()
add(x=5,y=6),add(y=5,x=6)
測試def add(x=4,y)
作用
參數的默認值可以在未傳入足夠的實數參數的時候,對沒有給定的參數賦值為默認值
參數非常多的時候,并不需要用戶每次都輸入所有的數,簡化函數調用
舉例
定義一個函數login,參數名為host,port,username,passwd
def login(host=’172.0.0.1′,port=’8080′,username=’wayne’,passwd=’123′):
????print(‘{}:{}@{}/{}’.format(host,port,username,passwd))
login(‘127.0.0.1′,’9999′,’zm’,’zhangmeng’)
可變參數
問題:有多個參數,需要累加求和
def add(nums):
????sum = 0
????for x in nums:
????????sum += x
????return sum
add([1,3,5])
在形參前使用*表示該形參是可變參數,可以接收多個實參
收集多個實參為一個tuple
關鍵字參數的可變參數
配置信息打印
def showconfig(**kwargs):
for k,v in kwargs.items():
Print(‘{} = {}’.format(k,v))
showconfig(host=’127.0.0.1′,port=’8080′,username=’zm’,passwd=’123′)
形參前使用**符號,表示可以接收多個關鍵字參數
收集的實參名稱和值組成一個字典
總結
有位置可變參數和關鍵字可變參數
位置可變參數在形參前使用一個*號
關鍵字可變參數在形參前使用兩個**
位置可變參數和關鍵字可變參數都可以收集若干個實參,位置可變參數收集形成一個元組,關鍵字可變參數搜集可以形成一個字典
混合使用參數時候,可變位置參數要放到參數裂變的最后,普通位置參數需要放到參數列表的前面,位置可變參數需要在關鍵字可變參數之前
舉例:
def fn(x,y,*args,**kwargs):
????print(x)
????print(y)
????print(args)
????print(kwargs)
fn(3,5,7,9,10,a=1,b=’python’)
fn(3,5)
fn(3,5,7)
Keyword-only參數(python3加入)
如果在一個*參數后,或者一個位置可變參數后,出現的普通參數,實際上已經不是普通的參數了,而是Keyword-only參數
def fn(x,*kwargs):
????print(x)
????print()
fn(5,5)
fn(3,5,7)
fn(3,5,x=7)#錯誤
如果fn的參數換位置,則x永遠得不到值,所以報錯
Keyword-only參數另一種形式
def fn(*,x,y):
Print(x,y)
fn(x=5,y=6)
*號之后,普通形參都變成了必須給出的Keyword-only參數
def fn(y,*args,x=5):
????print(‘x={},y={}’.format(x,y))
????print(args)
fn()
fn(5)
fn(x=6)
fn(1,2,3,x=10)
fn(y=17,2,3,x=10)
x是eyword-only參數
參數解構
def add(x,y):
????return x+y
add(4,6)
add(*[4,5])
add(*(4,5))
add(*{4,5})
add(*range(1,3))
給函數提供實參的時候,可以在集合類型錢使用*或者**,把集合類型的結構解開,提取出所有元素作為函數的實參
非字典類型使用*解構成位置參數
字典類型使用**解構成關鍵字參數
提取出來的元素數目要和參數的要求匹配,也要和參數的類型匹配
def add(x,y):
????return x+y
add(*(4,5))
add(*[4,5])
add(*(4,6))
d = {‘x’:5,’y’:6}
add(**d)
add(**{‘x’:5,’y’:6})
參數解構和位置可變參數
給函數提供實參的時候,可以在集合類型前使用*或者**,吧集合類型的結構解開,提取出所有元素作為函數的實參
def add(*nums):
????res = 0
????for x in nums:
????????res += x
????return res
add(1,2,3)
add(*[1,2,3])
add(*range(10))
上三角打印
def show(n):
????tail = ‘ ‘.join([str(i) for i in range(n,0,-1)])
????width = len(tail)
????for i in range(1,n):
????????print(“{:>{}}”.format(” “.join([str(j) for j in range(i,0,-1)]),width))
????print(tail)
show(12)
下三角打印
def showtail(n):
????tail = ” “.join([str(i) for i in range(n,0,-1)])
????print(tail)
????for i in range(len(tail)):
????????if tail[i] == ‘ ‘:
????????????print(‘ ‘*i,tail[i+1:])
showtail(12)
組合打印
def trangle(n):
????for i in range(1,n+1):
????????for j in range(n,0,-1):
????????????if i<j:
????????????????print(‘ ‘*len(str(j)),end = ‘ ‘)
????????????else:
????????????????print(j,end = ‘ ‘)
????????print()
????tail = ” “.join([str(i) for i in range(n,0,-1)])
????print(tail)
????for i in range(len(tail)):
????????if tail[i] == ‘ ‘:
????????????print(‘ ‘*i,tail[i+1:])
trangle(12) ???
Python函數返回值,作用域
函數的返回值
舉例:
def showplus(x):
????print(x)
????return x+1
showplus(5)
舉例:
def showplus(x):
????print(x)
????return x+1
????print(x+1)#并不會執行 ?ruturn直接終止了
showplus(5)
多條return語句
def guess(x):
????if x > 3:
????????return ‘>3’
????else:
????????return ‘<=’
print(guess(10))
多條return語句
def showpuls(x):
????print(x)
????return x+1
????return x+2
showplus(5)
舉例:
def fn(x):
????for i in range(x):
????????if i > 3:
????????????return i
????else:
????????print(‘{} is not greater than 3’.format(x))
print(fn(5))
print(fn(3))
函數的返回值總結
Pyhton函數使用return語句返回‘回值’
所有函數都有返回值,如果沒有return語句,隱式調用returnNone
Return語句并不一定是函數的語句塊的最后一條語句
一個函數可以存在多條return語句,但是只有一條可以被執行,如果沒有return被執行,隱式調用return None
如果有必要,可以顯示調用eturnNone,可以簡寫為return
如果函數執行的return語句,函數就會返回,當前被執行的return語句之后其他語句就不會被執行了
作用:結束函數調用,返回值
返回多個值
函數不能同時返回多個值
return [1,3,5]是指明返回一個列表,是一個列表對象
return 1,3,5 看似返回多個值,隱式的被python封裝成了一個元組
def showlist():
????return 1,3,5
x,y,z = showlist()
print(x,y,z)
函數嵌套
在一個函數中定義了另外一個函數
def outer():
????def inner():
????????print(‘inner’)
????print(‘outer’)
????inner()
outer()
函數有可見范圍,這就是作用域的概念
內部函數不能被外部直接使用,就會拋NameError異常
作用域
一個標識符的可見范圍,就是標識符的作用域。一般說的是變量的作用域
例子:
x = 5
def foo():
????print(x)
foo()
?
x = 5
def foo():
????x += 1
????print()
foo()
全局作用域
在整個程序運行環境中都可見
局部作用域
在函數,類等內部可見
局部變量使用范圍不能超過其所在的局部作用域
例子;
def fn():
????x = 1 ?#局部可見在fn內
def fn2():
????print(x)#不可見
#print(x)
fn2()
嵌套例子:
def outer1():
????o = 65
????def inner():
????????print(‘inner {}’.format(o))
????????print(chr(o))
????print(‘outer {}’.format(o))
????inner()
outer()
?
?
def outer2():
????o = 65
????def inner():
????????o = 97
????????print(‘inner {}’.format(o))
????????print(chr(o))
????print(‘outer {}’.format(o))
????inner()
outer()
從嵌套例子可以看出外層變量作用域在內層可見
內層作用域inner,如果定義了o=97,相當于作用域中重新定義了一個新的變量o但這個o并沒有覆蓋外層作用域中outer的o
全局變量global
使用全局作用域中必須有x的定義
使用global關鍵字的變量,將foo內的x聲明為使用外部的全局作用域中定義的x
例子
def foo():
????global x
????x =10
????x += 1
????print(x)
print(x)
但是,x=10賦值即定義,x在內部作用域作為一個外部作用域的變量賦值,所以x+=1不會報錯,這里的x的作用域還是全局的
global總結
X +=1 這種特殊形式產生錯誤的原因,先引用后賦值,而python動態語言是賦值才算是定義才能被引用,解決辦法,在這一條語句前增加x=0之類的賦值語句,或者使用global告訴內部作用域,去全局作用域查找變量定義
內部作用域使用x=5之類的賦值語句會重新定義局部作用域使用的變量x,但是,一旦這個作用域中使用global使用x為全局的,那么x=5相當于在為全局作用域的變量賦值
globa使用原則
外部作用域變量會內部作用域可見,但也不要在這個內部的局部作用域中直接使用因為函數的目的就是為了封裝盡量與外界隔離
如果函數需要使用外部全局變量,請使用函數的形參傳參解決
不用globa學習他就是為了深入理解變量的作用域
閉包
自由變量:未在本地作用域中定義的變量。例如定義在內存函數外的外層函數的作用域中的變量
閉包:就是一個概念,出現在嵌套函數中。指的是,內層函數引用到了外城函數的自用變量就形成了閉包,很多語言都有這個概念,最熟悉的就是JavaScript
def counter():
????c = [0]
????def inc():
????????c[0] += 1
????????return c[0]
????return inc
foo = counter()
print(foo(),foo())
c = 100
print((foo()))
nonlocal關鍵字
使用了nonlocal關鍵字,將變量標記為不再本地作用域定義。而在上級某一級局部作用域中定義但不能是全局作用域中定義
count是外層函數的局部變量,被內部函數引用
內部函數使用nonlocal關鍵字聲明count變量在上級作用域而非本地作用域中定義
1.?可以正常使用,且形成了閉包
2.?不能正常運行,變量a不能再全局作用域中
(1)def conter():
???? count = 0
???? def inc():
???????? nonlocal count
????????count += 1
????????return count
foo = counter()
foo()
foo()
(2)a = 50
def counter():
????nonlocal a
????a += 1
????print(a)
????count = 0
????def inc():
????????nonlocal count
????????count += 1
????????return count
????return inc
foo = counter()
foo()
foo()
默認值的作用域
def foo(xyz=[]):
????xyz.append(1)
????print(xyz)
foo()
foo()
print(xyz)#報錯,當前作用域沒有xyz變量
函數也是對象,python吧函數的默認值放在了屬性中,這個屬性就伴隨著這個函數對象的整個生命周期
查看foo.__defaults__屬性
def foo(xyz=[],u=’abc’,z=123):
????xyz.append(1)
????return xyz
print(foo(),id(foo))
print(foo.__defaults__)
print(foo(),id(foo))
print(foo.__defaults__)
__defaults__屬性中使用的元素組保存所有位置參數默認值,他不會因為在函數體內使用了它而發生改變
Xyz都是傳入參數或者默認的參數的副本,如果想修改原參數,無能為力
如果缺省值為None就創建一個醒的列表
第一種方法
使用影子拷貝創建一個新的對象,永遠不能改變傳入的對象
第二種方法
通過值得判斷就可以靈活的選擇創建對象或則修改傳入對象
這種方式靈活,應用廣泛
很多函數的定義,都可以看到使用None這個不可改變的值作為默認參數,可以說這是一種慣用法
函數的銷毀
def foo(xyz=[],u=’abc’,z=123):
????xyz.append(1)
????return xyz
print(foo(),id(foo),foo.__defaults__)
def foo(xyz=[],u=’abc’,z=123):
????xyz.append(1)
????return xyz
print(foo(),id(foo),foo.__defaults__)
del foo
print(foo(),id(foo),foo.__defaults__)
全局函數銷毀
重新定義同名函數
del語句是刪除函數對象
程序結束時
?
?
?
本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/96261