1.函數類型
函數也是一種類型,我們自定義的函數就是函數對象,函數名保存了函數對象的引用(地址)
def test():print('我是測試函數')
?
print(test) #函數名是變量,指向了函數對象
pf = test ? #pf變量也指向了函數對象,所以也可以通過pf調用test函數
pf()
2. 匿名函數
不再使用def 函數名()這種形式定義函數,而是使用lambda來創建匿名函數
特點:
-
lambda只是一個表達式,函數體比def定義的函數簡單的多
-
lambda的函數體不再是代碼塊,而是一個表達式
-
lambda只有一行,運行效率很高
語法:
lambda [arg1,arg2....argn]:表達式(只能是一個表達式)
add = lambda a,b:a + b
print(add(3,5))
3.傳入函數(理解)
一個函數就可以接收另一個函數作為參數,這種函數就稱之為高階函數,也可以稱之為傳入函數。可以實現通用編程,排序等復雜功能
#傳入函數,高階函數
#能被2整除數的和
def sum_even(n):sum = 0for i in range(1,n+1):if i % 2 == 0:sum += ireturn sum
?
#能被7整除的數的和
def sum_seven(n):sum = 0for i in range(1,n+1):if i % 7 == 0:sum += ireturn sum
#能被3和5整除,但不能7整除的數的和
def sum_fifteen(n):sum = 0for i in range(1,n+1):if i % 15 == 0 and i % 7 != 0:sum += ireturn sum
#通用求和函數
def sum1(n,callback):'''功能:求滿足callback規定條件的數的和:param n: 大于0的整數:param callback: 用于判斷一個數是否滿足指定條件,由調用者傳入,有一個參數,形如:def callback(n):return: 求和的結果'''sum = 0for i in range(1,n+1):if callback(i):sum += ireturn sum
print(sum1(100,lambda x:x%2==0))
print(sum1(100,lambda x:x%7==0))
print(sum1(100,lambda x:x%15==0 and x % 7 != 0))
4.閉包
我們可以在一個函數中再定義一個函數,在函數內部定義的函數稱之為內部函數,內部函數只能在函數內使用,不會污染外部空間。定義內部函數的函數稱之為外部函數,這樣的定義構成函數的嵌套
def outter(a): #外部函數x = 10def inner(y): #內部函數print(x + y)inner(a)outter(20)
-
內部函數只能在外部函數里調用,外界無法直接調用內部函數
在一個外部函數中定義了一個內部函數,內部函數里引用了外部函數的變量,并且外部函數的返回值是內函數的引用。這樣內部函數和其執行所需的環境變量就構成了一個閉包。
一般情況下,如果一個函數結束,函數的內部所有東西都會釋放掉,局部變量都會消失。但是閉包是一種特殊情況,如果外函數在結束的時候發現有自己的局部變量將來會在內部函數中用到,就把這個局部變量綁定給了內部函數,然后自己再結束。
def outter(a): #外部函數x = adef inner(y): #內部函數return x + y #引用外部變量return inner #返回內部函數(閉包)
pf = outter(20)
print(pf(10)) #30
print(pf(20)) #40
在閉包中無法直接修改外部變量x的值
def outter(a): #外部函數x = adef inner(y): #內部函數# x += 10 ? #UnboundLocalError: local variable 'x' referenced before assignmentreturn x + yreturn inner
在python3中可以通過nonlocal關鍵字聲明一下x,表示這個變量不是局部變量,需要向上一層變量空間找這個變量。
def outter(a): #外部函數x = adef inner(y): #內部函數nonlocal xx += 10return x + yreturn inner
5.偏函數
當一個函數有大量參數,調用的時候非常不方便,可以使用偏函數技術,將一些參數固定(給默認值),達到簡化函數調用的目的。
import functools
def test(a,b,c,d):print(a, b, c, d)
#從前面固定參數,使用位置參數就行,1=>a,2=>b
test1 = functools.partial(test,1,2)
test1(3,4) #3=>c 4=>d
?
#從后面固定參數,需要使用關鍵字參數
test2 = functools.partial(test,c=3,d=4)
test2(1,2) #1=>a 2=>b
?
#如果固定的參數不連續,則需使用關鍵字參數固定
test3 = functools.partial(test,b=2,d=4)
test3(a=1,c=3) #需要使用關鍵字參數,否則會報錯
6.變量的作用域
程序中的變量并不是在任意的位置都可以隨意訪問,在哪里可以訪問取決于這個變量的作用域,變量的作用域指的是變量在那段代碼中可以使用,可以使用變量的那段代碼就是變量的作用域。在python中,只有函數/類/模塊才引入作用域,if/elif/else , while/for,try/except等并不會引入新的作用域
#if語句不引入新作用域,msg在外面可以使用
if True:msg = "message"
?
print(msg)
6.1 變量作用域的分類
按照作用域劃分,可以分為:
-
L:Local,局部作用域
-
E:Enclosing,閉包作用域【閉包的外部函數中定義的變量】
-
G:Global,全局作用域 在所有函數外定義的變量
-
B:Built-in,內建作用域【內置作用域】
#1 局部作用域 ?
#局部變量只能在函數內部使用,外部無法引用
#局部變量的作用域從定義開始到函數體結束
def demo():num = 20 #局部變量 ?print(num)
demo()
#print(num) 錯誤
?
#閉包作用域
def outter():x = 10 ? #函數作用域,從定義開始到本函數結束def inner():y = x #在閉包中可以引用print(y)return inner
pf = outter()
pf() #執行閉包
print(pf.__closure__)
?
#全局作用域
x = 100 ? #全局作用域 從定義開始到本文件結束
def demo():print(x)
print(x)
?
#內建作用域,是指系統內建的函數或常量,在系統載入時加載,在所有模塊中都可以直接引用
#比如說系統函數
print(max(1,2,3)) #max函數就是內建作用域 哪里都可以引用
def demo():x = 30y = 50print(max(x, y))
6.2 變量作用域查找規則
以 L --> E --> G -->B 的規則查找,即:在局部找不到,便會去局部外的局部找(例如閉包),再找不到就會去全局找,最后到內建作用域中找。
6.3 全局變量和局部變量
定義在函數內部的變量擁有一個局部作用域,被稱為局部變量
定義在函數外面的變量擁有一個全局作用域,被稱為全局變量
局部變量和全局變量同名,局部優先
total = 0 ? #全局變量
def sum(arg1,arg2):total = arg1 + arg2 ? #局部變量print("函數內部:",total)return totalsum(10,20)
#print(total1)
print("函數外部:",total)
?
num = 1
def fun1():print(num) #UnboundLocalError: local variable 'num' referenced before assignmentnum = 123print(num)
?
fun1()
6.4 global和nonlocal
#1.在Python中,當內部作用域想修改全局變量的時候,則就要使用global關鍵字進行聲明
num = 1
def fun1():global num ? #告訴編譯器,此處的num是全局變量print(num) ? #1num = 123print(num) #123fun1()
?
a = 10
def test():global aa = a + 1print(a)
test()
?
#2.如果要修改函數作用域中的變量,則使用nonlocal
#需要明確的是,nonlocal關鍵字定義在閉包里面
x = 0 #全局作用域
?
def outer():x = 1 ? #閉包作用域
?def inner():nonlocal xx = 2 ? #局部作用域print("inner:",x) #2
?inner()print("outer:",x) #1---->2
?
outer()
print("全局:",x) #0
?
#nonlocal關鍵字:聲明了該變量不只是在outer函數中有效,在inner函數內部也有效