##函數
– 函數
— 數學定義:y=f(x),y是x的函數,x是自變量
— python函數:由若干語句組成的語句塊、函數名稱、參數列表構成,它是組織代碼的最小單元;完成一定的功能
– 函數的作用
— 結構化編程對代碼的最基本的封裝,一般按照功能組織一段代碼
— 封裝的目的是為了復用,減少冗余代碼
— 代碼簡潔,美觀
– 函數的分類
— 內建函數,如min()
— 庫函數,如math.ceil()等
##函數定義、調用
– def語句定義函數
—
def函數名(參數列表)
函數體(代碼塊)
[return 返回值]
— 函數名就是標識符,命名要求一樣
— 語句塊必須縮進,約定4個空格
— Python的函數沒有return語句,隱式會返回一個None值
— 定義中的參數列表成為形式參數,只是一種符號表達,簡稱形參
– 調用
— 函數定義,只是聲明了一個函數,它不會被執行,需要調用
— 調用的方式,就是函數名加上小括號,括號內寫上參數
— 調用時寫的參數是實際參數,是傳入的值,成為實參
##函數參數
– 參數調用時傳入的參數要和定義的個數相匹配(可變參數例外)
– 位置參數
— 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]) 要求位置參數必須在關鍵字參數之前傳入,位置參數是按位置對應的
##函數參數默認值
— 定義時,在形參后面跟上一個值
def add(x=4,y=5)
return x+y
— 作用 參數的默認值可以在未傳入足夠的實參的時候,對沒有給定的參數賦默認值
—
def login(host=’127.0.0.1′,port=’8080′,username=’wayne’,passwor=’magedu’):
print(‘{}:{}@{}/{}’.format(host, port, username, password))
login()
login(‘127.0.0.1’, 80, ‘tom’, ‘tom’)
login(port=80, password=’magedu’, host=’www’)
##可變參數
– 可變參數
— 一個參數可以匹配任意個參數
– 位置參數的可變參數
— 在形參前使用*表示該形參是可變參數,可以接收多個實參
— 收集多個實參為一個tuple
– 關鍵字參數的可變參數
— 配置信息打印
—
def showconfig(**kwargs):
for k,v in kwargs.items():
print(‘{}={}’.format(k,v))
showconfig(host=’127.0.0.1′,port=’8080′,username=’wayne’,password=’magedu’)
— 形參前使用**符號,表示可以接收多個關鍵字參數
— 收集的實參名稱和值組成一個字典
– 總結
— 有位置可變參數和關鍵字可變參數
— 位置可變參數在形參前使用一個*
— 關鍵字可變參數在形參前使用兩個星號**
— 位置可變參數和關鍵字可變參數都可以收集若干個實參,位置可變參數收集形成一個tuple,關鍵字可變參數收集形成一個dict
— 混合使用參數的時候,可變參數要放到參數列表的最后,普通參數需要放到參數列表前面,位置可變參數需要在關鍵字可變參數之前
-舉例
—
def fn(x,y,*args,**kwargs):
print(x)
print(y)
print(args)
print(kwargs)
fn(1,2,3,4,5,a=1,b=”abc”)
fn(3,5)
fn(3,2,a=1,b=’abc’)
fn(2,3,x=5,y=6,a=1,b=”asf”) #由于x,y重復賦值 錯誤
def fn(*args, x, y, **kwargs):
print(x)
print(y)
print(args)
print(kwargs)
fn(3,5) #錯誤
fn(3,4,5) #錯誤
fn(3,5,a=1,b=’python’) #錯誤
fn(7,9,y=5,x=3,a=1,b=’python’) #正確
– keyword-only參數
— 如果在一個星號參數后,或者一個位置可變參數后,出現的普通參數,實際上已經不是普通的參數了,而是keyword-only參數
—
def fn(*args, x):
print(x)
print(args)
fn(3,5) #錯誤 缺少x
fn(3,5,7) #錯誤 缺少x
fn(3,5,x=7) #正確
— 出現def fn(**kwargs,x) 這個情況是錯誤的。
– keyword-only 另一種形式
— def fn(*,x,y) ‘*’之后的普通參數都變成必須給的keyword-only參數
##函數參數
– 參數規則
— 參數列表一般順序是,普通參數,缺省參數,可變位置參數,keyword-only參數,可變關鍵字參數
—
def fn(x, y, z=3, *arg, m=4, n, **kwargs):
print(x,y,z,m,n)
print(args)
print(kwargs)
##參數解構
– 給參數提供實參的時候,可以在集合類型前使用*或者**,把集合類型的結構解開,提取出所有元素作為函數的實參
– 非字典類型中使用*解構成位置參數
– 字典類型使用**解構成關鍵字參數
– 提取出來的元素數目要和參數的要求匹配,也要和參數的類型匹配
##練習
-編寫一個函數能夠接收至少2個參數,返回最小值和最大值
—
import random
def show(*nums):
print(nums)
return max(nums),min(nums)
print(*show(*[random.randint(1,100) for _ in range(5)]))
-編寫一個函數,接收一個參數n,n為正整數,兩種打印方式,必須對齊。
上三角
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 fn(n): #法二
for i in range(1,n+1):
for j in range(n,0,-1):
if i >= j:
print(‘{}’.format(str(j)),end=” “)
else:
print(‘{}’.format(‘ ‘*len(str(j))),end=” “)
print()
fn(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 fn(n): #法二
for i in range(n,0,-1):
for j in range(n,0,-1):
if i >= j:
print(‘{}’.format(str(j)),end=” “)
else:
print(‘{}’.format(‘ ‘*len(str(j))),end=” “)
print()
fn(12)
##插入排序
– 原理
— 在未排序序列中,構建一個子排序序列,直至全部數據排序完成;將待排序的數,插入到已經排序的序列中合適的位置;增加一個哨兵,放入待比較的值,讓它和后面已經排好的序列比較,找到合適的插入點
– 性能
— 最好的情況,n-1次;最差的情況n(n-1)/2;
— 使用兩層嵌套循環,時間復雜度O(n^2)
— 穩定排序算法
— 使用在小規模的數據比較
— 可以用二分法來優化
實現
lst = [1,5,2,9,7,8,4,6,3]
lst = [0] + lst
for i in range(2,len(lst)):
lst[0] = lst[i]
j = i – 1
if lst[j] > lst[0]:
while lst[j] > lst[0]:
lst[j+1] = lst[j]
j -= 1
lst[j+1] = lst[0]
print(lst[1:])
##函數返回值
– python函數使用return語句返回“返回值”
– 所有函數都有返回值,如果沒有return語句,隱式調用return None
– return語句不一定是函數的語句塊的最后一條語句
– 一個函數可以存在多個return語句,但是只有一條可以被執行。
– return None可以簡寫成return
– 如果函數執行return語句,函數就會返回,當前被執行的return語句之后的其它語句就不會被執行了
– 作用:結束函數調用、返回值
– return [1,3,5] 是指返回了一個列表,是一個列表對象
– return 1,3,5 其實是被python封裝成了一個元組
## 解構
def showlist():
return 1,2,3
x,y,z = showlist() #使用解構提取更為方便
## 舉例
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)) 結果返回了4
# print(fn(3)) 結果是3 is not greater than 3
##函數嵌套
– 在一個函數中定義了另外一個函數
##
def outer():
def inner(): #內部函數不能被外部直接使用,會拋出NameError異常
print(“inner”)
print(“outer”)
inner()
outer()
inner()
##作用域
– 一個標識符的可見范圍,這就是標識符的作用域。一般常說的是變量的作用域
– 全局作用域:整個程序運行環境中都可見
– 局部作用域:在函數、類等內部可見,局部變量使用范圍不能超過其所在的局部作用域
##
def outer1():
o = 65
def inner():
print(“inner {}”.format(o)) #此處的o調用outer1函數里的o
print(chr(o))
print(“outer {}”.format(o))
inner()
outer1()
def outer2(): #
o = 65
def inner():
o = 97 #這個o是重新定義的,沒有覆蓋上面的o
print(“inner {}”.format(o)) #此處的o調用本地o的值97
print(chr(o))
print(“outer {}”.format(o))
inner()
outer2()
**錯誤舉例**

– 它相當于在foo函數內部定義了局部變量x,所以foo內部所有x都是這個局部變量x。但是這個x還沒有被完成賦值,就做加1操作。發生錯誤
**改變方法:global**
##
x=5
def foo():
global x #全局變量
x = 10 #賦值即定義,把x重新變成10
x += 1
print(x) #輸出11
print(x)
##global使用原則
– 外部作用域變量會內部作用域可見,但也不要在這個內部的局部作用域中直接使用,因為函數的目的就是為了封裝,盡量與外界隔離
– 如果函數需要使用外部全局變量,請使用函數的形參傳參解決
##閉包
– 自由變量:未在本地作用域中定義的變量。例如定義在內層函數外的外層函數的作用域中的變量
– 閉包:內層函數引用到了外層函數的自由變量,就形成了閉包。
##例子
def counter():
c = [0]
def inc():
c[0] += 1 #c已經定義,inc中的使用方式為c的元素修改值
return c[0]
return inc
foo = counter()
print(foo(),foo()) # 打印 1 2
c = 100
print(foo()) # 打印 3 它引用的是inc中的變量c
##**nonlocal關鍵字**
– 使用nonlocal關鍵字,將變量標記為在上級的局部作用域中定義,但不能全局中定義
##舉例
def counter():
count = 0
def inc():
nonlocal count #它聲明count變量在上一級作用域中
count += 1 #形成了閉包
return count
return inc
foo = counter()
foo()
foo()
##默認值的作用域
##舉例
def foo(xyz = []):
xyz.append(1)
print(xyz)
foo() # [1]
foo() # [1,1]
print(xyz) #報錯,xyz沒有定義
#為什么打出[1,1]因為,函數也是對象,python把函數的默認值放在了屬性中,這個屬性就伴隨著這個函數對象的整個生命周期。查看foo.__defaults__
## 默認值引用類型
def foo(xyz=[], u=’abc’, z=123):
xyz.append(1) # xyz默認值是引用類型,元組不會變化。
return xyz
print(foo(), id(foo))
print(foo.__defaults__)
print(foo(), id(foo))
print(foo.__defaults__)
## 默認值的作用域
– 可變類型默認值,如果使用默認值,就可能修改這個默認值
– 有時候這個特性好,但是有副作用
##解決方法兩種
def foo(xyz=[], u=’abc’, z=123):
xyz = xyz[:] # 影子拷貝
xyz.append(1) # xyz都是傳入參數或者默認參數副本,不能修改原參數
print(xyz)
foo()
print(foo.__defaults__)
foo()
print(foo.__defaults__)
foo([10])
print(foo.__defaults__)
foo([10,5])
print(foo.__defaults__)
(2)
def foo(xyz=None, u=’abc’, z=123):
if xyz is None: #使用不可變類型的默認值
xyz = [] # 若缺省值None就創建一個列表
xyz.append(1) #如果傳入一個列表,就修改這個列表
print(xyz)
##函數的銷毀
### 全局銷毀
– 重新定義同名函數
– del語句銷毀函數對象
– 程序結束時
### 局部銷毀
– 重新再上級作用域定義同名函數
– del語句刪除
– 上級作用域銷毀時
本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/87921