python學習筆記3 函式 閉包 裝飾器
阿新 • • 發佈:2018-12-12
函式
def foo3():#函式名與引數
#函式體
cumsum=0
for i in range(15):
cumsum+=i
#return返回的是物件,(如返回物件數>1返回元組)
return cumsum,cumsum*2
return cumsum-1 #不返回
##yield 生成器
def foo4():
for i in range(5):
yield i
yield 'f' #再加入一個yield看看會不會被執行
i+=1
g1= foo4()#返回(generator object foo4 at 0x0000000002555E60)
type(g1)#<class 'generator'>
next(g1)#繼續上一次的位置,進入下一層迴圈
#執行完最後一次迴圈,結束 yield語句並丟擲StopIteration 異常
函式的引數
- 位置引數
- 關鍵字引數
- 位置引數包裹*
- 關鍵字引數包裹**
##位置引數
def foo3(companyName,websiteUrl):#位置引數的定義
print('公司名:',companyName,'公司網址:',websiteUrl)
foo3('七月線上' ,'http://www.julyedu.com')
foo3('http://www.julyedu.com',websiteUrl='七月線上')
#位置引數,對位置敏感,傳遞時不用指定引數名
##關鍵字引數
def foo4(companyName,websiteUrl,intro='專注AI教育'):#關鍵字引數的定義
print('公司名:',companyName,'公司網址:',websiteUrl,'介紹:',intro)
foo4('七月線上','http://www.julyedu.com')#不傳關鍵字引數,函式依舊可以被呼叫,採用預設值
foo4('七月線上','http://www.julyedu.com' ,intro='國內領先的AI教育平臺')#傳關鍵字引數,覆蓋預設值
##位置引數包裹*
def mysum1(a,b,c):
return a+b+c
mysum1(5,7,15)
#mysum1(5,7) #報錯,因為傳入的引數少於函式定義時的個數
#mysum1(5,7,15,22) #報錯,因為傳入的引數多於函式定義時的個數
#這時我們就需要使用包裹進行接收
def mysum2(*args):
print(type(args)) # #<class 'tuple'>
return sum(args)
mysum2(5,7,15,22,33)#正常呼叫
mysum2(5,7)#正常呼叫
#傳遞引數時使用包裹-位置引數
l1=[1,5,6,7,2,5,3.5,9,3,4]
mysum2(*l1) #將列表打碎 每一個元素是一個tuple 返回的是(1,5,6,7,2,5,3,5,9,3,4)
#zip案例
l1=[(1,3),(2,4)]
list(zip(*l1)) #將列表l1打碎 再拼接起來
##那同樣如果想一次性傳入不定長關鍵字引數,也可以使用一個包裹進行接收
##關鍵字引數包裹**
def filmInfo(**kwargs):
print(type(kwargs)) #<class 'dict'>
for key,values in kwargs.items():
print(key,':',values)
filmInfo(film='羞羞的鐵拳',box=3.5)
filmInfo(film='羞羞的鐵拳',box=3.5,rate=7.9)
d1={'羞羞的鐵拳':3.5,'雷神3':3.1,'戰狼2':60} #一定要注意字典和關鍵字引數傳入的不同
filmInfo(**d1)
#包裹解包順序
#首先拆位置引數包裹,按順序給必選,預設,可變。
#再抓給關鍵字引數包裹
def scoreReport(name,age,*args,course='python',**kwargs):
print('個人資訊:',name,age)
for item in args:
print(item)
print('課程資訊:',course)
print('每節課成績:')
for key,value in kwargs.items():
print (key,value)
scoreReport('xiaoming',22,'高中部','三年二班',Lesson1=80,Lesson2=85)
scoreReport('xiaoming',22,'三年二班',course='machine learning',Lesson1=80,Lesson2=85)
引數傳遞的處理
重要
##值傳遞,引數本身不會被修改
a=7
b='julyedu'
print('before reference:',a,b)
def foo1(a,b):
a+=1
b+='.com'
print('In foo1 a,b has changed to',a,b)
foo1(a,b)
print('after reference:',a,b) #after reference: 7 julyedu #非常重要
#結論:值傳遞時,變數傳遞給函式後,函式複製一份,不會影響原有變數
##指標傳遞引數,會修改引數本身
l1=[1,2,3.4]
d1={'name':'jack'}
def foo2(a,b):
a.pop()
b['age']=22
print('before reference:',l1,d1) #before reference: [1, 2, 3.4] {'name': 'jack'}
foo2(l1,d1)
print('after reference:',l1,d1) #after reference: [1, 2] {'name': 'jack', 'age': 22}
#結論:指標(或引用)傳遞時,變數傳遞給函式的是及引用,該引用可以改變原變數
變數的作用域
全域性變數 區域性變數 區域性變數可以覆蓋全域性變數 區域性作用域->全域性作用域
偏函式PFA
使用場景:如果一個函式的引數很多,而在每次呼叫的時候有一些又經常不需要被指定時,就可以使用偏函式(近似理解為預設值) 語法:partical(func,*args,**keywords) 使用:from functools import partial import functools
#Partial function application(PFA)
# 只設置了一部分的引數的函式
# 固定一部分引數,使得被呼叫時,某些引數被固定住了。
#例如我們要定義一個函式將傳進來的16進位制的字串,轉換為10進位制的
def hex2int(num):
return int(str(num),base=16)#base為關鍵字引數,這個在呼叫int這個函式時,固定給16。因為這個函式就是用來轉換16進位制到10進位制
hex2int('F')#這時呼叫,相當於實際上會把10作為*args的一部分自動加到左邊,也就是:int('F',base=16),這樣就少寫了一個函式
#這時也可以使用偏函式,固定int函式的關鍵字引數base,可以這樣定義:
import functools
hex2int2=functools.partial(int,base=16)
hex2int2('A') #10
#偏函式可以固定位置引數
max100=functools.partial(max,100)#定義一個叫max100的偏函式,將這個偏函式的第一個值固定為100
max100(101)#這時呼叫它,傳入的值,都會與100進行比較反並返回。
type(max100)#偏函式的型別與普通函式不一樣 #<class 'functools.partial'>
遞迴函式
#遞迴的方法求一個列表中數值的累加
def foo1(num):
if len(num)==1:
return num[0]
else:
return num[0]+foo1(num[1:]) #切片
foo1([1,2,31,5,6,55]) #100
#使用遞迴分解質因數
l1=[]
def fenji(num):
num=int(num)
for i in range(2,num):
if num%i==0:
l1.append(i)
nextv=int(num/i)
fenji(nextv)
break#這裡的break不加就會硬迴圈60次
return l1
fenji(60)
#階乘
def factorial(n):
if n==1:
return 1
else:
return n*factorial(n-1)
factorial (5)
匿名函式lambda
#匿名函式
print(type(lambda a,b:a**b )) #function
#不用寫return
#使用1:作為正常函式使用,不推薦
foo=lambda x,y:x+y #不用寫return
print(foo(5,6)) #11
#使用2:lambda關鍵字定義在高階函式的引數位上
d1={'china':15,'India':9,'USA':2,'Japan':1.5}
sorted(d1.items(),key=lambda x:(x[0],x[1]))#按d1.items()第0個元素升序,國家名
# sorted(d1.items(),key=lambda x:(x[1]))#按d1.items()第1個元素升序,人口數
高階函式
函式名可以向變數一樣,在函式中作為引數,傳來傳去
##高階函式
def mycalucate(num,func):
return func #num作為引數再傳入func中
l1=[5,8,3,6,9,15,22]
mycalucate(l1,max)
mycalucate(l1,min)
mycalucate(l1,sum)
mycalucate(l1,reversed)
##回撥函式
#函式作為呼叫函式的結果返回
def callbackfunc(*num):
return max #返回的是函式 所以叫回調函式
list(callbackfunc(53,5,33)) #53
BIFs-高階函式
filter:對每個元素做過濾 map:對每個元素做對映 一種更高階的列表推導式 reduce:兩兩傳給func Python 3.x中,reduce()函式已經被從全域性名字 空間裡移除了,它和partical一樣被放置在fucntools模組中。使用前需要呼叫
l1=[2,3,5,7,3,4,5,9,'julyedu.com',[2,3,3],5,2]
##filter
#語法:filter(function,list)
# 函式 f 的作用是對每個元素進行判斷,返回 True或 False
# filter()根據判斷結果自動過濾掉不符合條件的元素,返回由符合條件元素組成的新list。
def myfilter(x):
if x>60:
return True
else:
return False
filter(myfilter,l1)
list(filter(lambda x:True if type(x)==str else False,l1))
##map
# 語法:map(function, list)
#讓list的每一個元素依次呼叫function函式,並獲取返回值存入一個新的list中。
map(lambda x:(x,l1.count(x)),l1) #統計列表中每個元素出現的次數 輸出(x,它出現的次數)
## reduce
# 語法:reduce(function, list)
#函式function必須包含兩個引數,optional可選,如果存在則表示初值為optional
#reduce()對list的每個元素反覆呼叫函式f,並返回最終結果值。
from functools import reduce
reduce(lambda a,b:a+b,[1,2,3,4,5,6,7,8]) #lambda輸入的是兩個引數 輸出的是列表的求和
閉包Closure
nums_in_global=[15,2,3,9,3.2]#宣告一個全域性
def foo1(nums_in_function):
print('nums_in_function此時在是foo1中,可以被 訪問:',nums_in_function)
def foo2():
return max(nums_in_function)#雖然沒有給foo2傳入任何引數,但foo2卻能訪問到foo1中的變數nums_in_function
# return max(nums_in_global)#雖然沒有給foo2傳入任何引數,但foo2卻能訪問到全域性變數nums_in_global
return foo2 #返回定義函式裡面的函式物件
#呼叫
foo1([5,3,8])()
裝飾器
現有如下 三個函式
def foo1():
print ('this is foo1 function')
def foo2():
print ('this is foo2 function')
def foo3():
print ('this is foo3 function')
#現在想為每一個函式都新增一個列印當前時間的功能
#我們可以這樣解決
import datetime
def extrafoo(func):
def inner():
print('from inner to execute:',func.__name__) #func.__name__是傳入引數的名字
print('the',func.__name__,'result:',func())
print('extra:',datetime.datetime.now())
return inner
@extrafoo #裝飾器特性,被裝飾的函式定義之後立即執行。
def foo1():
return 'this is foo1 function--'
#@是python裝飾器的簡便寫法,也叫語法糖
#裝飾器語法糖在要被包裹的函式前宣告。@後面的函式名,是包裹下邊函式的函式名extrafoo
#該語法糖省略了
#decorated=foo(test)
#decorated()
# 裝飾器在Python使用如此方便都要歸因於
# Python的函式能像普通的物件一樣能作為引數傳遞給其他函式
# 可以被賦值給其他變數,可以作為返回值,可以被定義在另外一個函式內。
foo1()