Python基礎知識總結筆記(四)函式
python中的函式
函式中的引數
變數作用域
偏函式PFA
遞回函式
高階函式
BIFs中的高階函式
匿名函式lambda
閉包Closure
裝飾器Decorator
函式式編程Functional Programming
每天都有程式員定時講解Python技術,分享一些學習的方法和需要留意的小細節,要資料加 624440745
1. python中的函式
? 函式的意義:
■1.對輸入進行變換映射后輸出 ,可以進行反復呼叫,以函式名對代碼塊進行封裝
■2.程序化 VS 結構化
? 函式的創建及結構:
■定義函式名:def foo1(num):
■引數:num
■函式體
■回傳
□有無回傳:
有回傳值:return回傳的是物件,(如回傳物件數>1回傳元組),且回傳的為最后的一個return值,
無回傳值 :無回傳值或者return后為空,
print可以有很多,但是return只有一個,
□return與yield的區別:
print:不回傳任何的函式
return 結束函式,回傳值,當函式被呼叫時,遇到結尾或return時就準備結束了,只顯示最后一個return的值,
yield:丟出一個數,物件變成了生成器–記錄當前運行到哪里了,
#函式的意義
n=5
for i in range(n):
print(i)
# 以函式名對以上代碼塊進行封裝
def foo(num): #函式名foo; 引數num
for i in range(num):
print(i)
#然后進行反復呼叫
# foo()
#對輸入進行變換映射后輸出
#函式的定義
def foo1(num):#函式名與引數
#函式體
cumsum=0#函式內部的變數
for i in range(num):
cumsum+=i
#回傳值
return cumsum
foo1(15)
#函式的回傳值-無回傳值
def foo2():#函式名與引數
#函式體
cumsum=0
for i in range(15):
cumsum+=i
#無回傳值
#或者return后為空
foo2()
#函式的回傳值,有回傳值
def foo3():#函式名與引數
#函式體
cumsum=0
for i in range(15):
cumsum+=i
#return回傳的是物件,(如回傳物件數>1回傳元組)
return cumsum,cumsum*2
#函式結束
foo3()
#return與print在Notebook上的差異
#print可以有很多,但是return只有一個
# def foo2():
# for i in range(5):
# print(i)
# foo2()
# #函式的引數
# def foo3(num):
# for i in range(num):
# print(i)
# return 'Done'
# foo3(1)
# print(foo3(2))
### 函式的回傳
#return與yield關鍵字
#return 結束函式
def foo1():#不回傳任何的函式
print('i\'m foo1,but i return nothing')
def foo2():#使用return回傳值
return 'i\'m foo2, this is what i return'
def foo3():#函式被呼叫時,遇到結尾或return時就準備結束了,
return 'i\'m foo3, this is the first return'
return 'i\'m foo3, this is the secod return'
#yield 丟出一個數--物件變成了生成器--記錄當前運行到哪里了
def foo4():
for i in range(5):
return i#執行第一次時foo4函式就結束了
#yield
def foo4():
for i in range(5):
yield i
yield 'f' #再加入一個yield看看會不會被執行
i+=1
g1=foo4()#看一下呼叫foo4()回傳的是什么
type(g1)#看一下g1是個什么樣子的物件
next(g1)#繼續上一次的位置,進入下一層回圈
#執行完最后一次回圈,結束 yield陳述句并拋出StopIteration 例外
2. 函式中的引數
? 引數:
■語法:
func(positional_args,keyword_args,*tuple_nonkw_args,**dict_kw_args)
positional_args位置引數
keyword_args關鍵字引數
tuple_nonkw_args非關鍵字不定長引數
dict_kw_args關鍵字不定長引數
? 按引數傳遞方式:
■位置引數(定位引數,非關鍵字引數) :位置順序十分重要,不可缺少個數,對位置敏感,傳遞時不用指定引數名
■關鍵字引數:等于號確定,intro=" "
不傳關鍵字引數,函式依舊可以被呼叫,采用默認值,
傳關鍵字引數,則覆寫默認值,
■位置引數包裹及使用*:一次傳入不定長個位置引數,傳入n個位置引數,傳進來串列[]
■關鍵字引數包裹及使用 **:一次性傳入不定長關鍵字引數傳入n個關鍵字引數,傳進來字典{}
位置引數包裹可以寫n個——串列;關鍵字引數包裹可以寫n個——字典
■包裹解包順序:首先拆位置引數包裹,按順序給必選,默認,可變,再抓給關鍵字引數包裹,
■傳遞不定長引數時,使用包裹:位置引數
■傳遞引數時,使用包裹:關鍵字型引數
傳遞不定長引數時使用包裹——位置引數必須打碎(只傳遞內容)再傳遞,傳遞引數同理,即:串列型別、tuple型別必須(*list);字典型別必須( * *字典),若傳(list)代表的是傳物件對不上函式,
l1=[1,5,6,7,2,5,3.5,9,6,3,4]
mysum2(*l1)#mysum2(1,5,6,7,2,5,3.5,9,6,3,4)可以,但是mysum2(l1)不可以,因為相當于是傳遞了l1為一個list型別的物件,*l1表示可迭代物件,里面有多少物件就當多少物件接受,
1
2
? 按引數的型別:
■必選(位置引數):必須寫、個數要對應
■關鍵字/默認:*args可變長位置引數,**kwargs可變長關鍵字引數
其中:
*args串列
**kwargs字典
? 函式如何處理傳入引數
■值傳遞引數與指標傳遞引數:
值傳遞引數:值傳遞時,變數傳遞給函式后,函式復制一份,不會影響原有變數,
指標傳遞引數,會修改引數本身:指標(或參考)傳遞時,變數傳遞給函式的是及參考,該參考可以改變原變數
#按引數傳遞方式
#位置引數
def foo3(companyName,websiteUrl):#位置引數的定義
print('公司名:',companyName,'公司網址:',websiteUrl)
foo3('七月在線','http://www.julyedu.com')
foo3('http://www.julyedu.com',websiteUrl='七月在線')
#位置引數,對位置敏感,傳遞時不用指定引數名
#關鍵字引數
def foo4(companyName,websiteUrl,intro='專注AI教育'):#關鍵字引數的定義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) #報錯,因為傳入的引數多于函式定義時的個數
#這時我們就需要使用包裹*args(tuple型別)進行接收
#位置引數包裹可以寫n個——串列;關鍵字引數包裹可以寫n個——字典
def mysum2(*args):
# print(type(args))
return sum(args)
mysum2(5,7,15,22,33)#正常呼叫
mysum2(5,7)#正常呼叫
#那同樣如果想一次性傳入不定長關鍵字引數,也可以使用一個包裹進行接收
#關鍵字引數包裹及使用**
def filmInfo(**kwargs):
print(type(kwargs))
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,'box':3.5}
#包裹解包順序
#首先拆位置引數包裹,按順序給必選,默認,可變,
#再抓給關鍵字引數包裹
def scoreReport(name,age,*args,course='python',**kwargs):
#位置;位置;位置引數包裹;關鍵字(默認,可以不修改);關鍵字引數包裹
#位置引數包裹可以寫n個——串列;關鍵字引數包裹可以寫n個——字典
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)
# #傳遞不定長引數時使用包裹-位置引數 必須打碎(只傳遞內容)再傳遞,即串列型別必須(*list);字典型別必須(**字典),若(list)代表的是傳物件對不上函式,
l1=[1,5,6,7,2,5,3.5,9,6,3,4]
mysum2(*l1)#=mysum2(1,5,6,7,2,5,3.5,9,6,3,4)
# #zip案例
# l1=[(1,3),(2,4)]
# list(zip(*l1))
# ##傳遞引數時使用包裹-關鍵字型引數
# d1={'羞羞的鐵拳':3.5,'雷神3':3.1,'戰狼2':60}
# filmInfo(**d1)
#值傳遞,引數本身不會被修改
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)
#結論:值傳遞時,變數傳遞給函式后,函式復制一份,不會影響原有變數
print('>'*40)
#指標傳遞引數,會修改引數本身
l1=[1,2,3.4]
d1={'name':'jack'}
def foo2(a,b):
a.pop()
b['age']=22
print('before reference:',l1,d1)
foo2(l1,d1)
print('after reference:',l1,d1)
#結論:指標(或參考)傳遞時,變數傳遞給函式的是及參考,該參考可以改變原變
3. 變數作用域
位置與順序
? 識別符號的作用域
globals()#全域變數名稱空間
locals()#區域變數名稱空間
? 全域變數
■定義:全域變數會一直存在,除非是腳本運行結束或 del 洗掉它,
■經過函式時:可以被函式內部呼叫
? 區域變數
■函式內部創建與訪問,當被呼叫結束時,生命周期結束,
? 變數的搜索順序
■覆寫問題:重名,從區域到全域:先從區域找,找不到再去全域找,
■區域作用域->全域作用域:從區域到全域
4. 偏函式PFA
? 偏函式Partial function application
■使用場景:如果一個函式的引數很多,而在每次呼叫的時候有一些又經常不需要被指定時,就可以使用偏函式(近似理解為默認值)有些引數無需修改,固定部分引數
只設定了一部分的引數的函式,固定一部分引數,使得被呼叫時,某些引數被固定住了,
■語法:partical(func,*args,**keywords)
■使用:from functools import partial
■原理:創建一個新函式,固定住原函式的部分引數(可以為位置引數,也可以是關鍵字引數),偏函式的型別與普通函式不一樣,為:functools.partial,
#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')
#偏函式能固定位置引數?
#可以
max100=functools.partial(max,100)#定義一個叫max100的偏函式,將這個偏函式的第一個值固定為100
max100(101)#這時呼叫它,傳入的值,都會與100進行比較反并回傳,
type(max100)#偏函式的型別與普通函式不一樣
5. 遞回函式
? 定義:
■函式在內部呼叫自身
? 例子:
■求一個串列中數值的累加
#遞回的方法求一個串列中數值的累加
def foo1(num):
if len(num)==1:
return num[0]
else:
# print(num[0],'>'*6)
# print(num[1:],' >'*6)
return num[0]+foo1(num[1:])
foo1([1,2,31,5,6,55])
#使用遞回分解質因數
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)
6. 高階函式
? 函式的參考與呼叫
■參考:訪問,變數別名(多個別名參考)
一個物件可以被多個變數參考,
■呼叫:() 最后回傳結果
? 函式物件可以被參考,可以作為引數被傳入或作為結果被回傳,
? 高階函式:
■==一個函式接收另一個函式作為引數,==將函式作為變數,可接受一個指向函式變數的變數名
? 回呼函式:
■函式作為呼叫函式的結果回傳,回傳函式
#函式物件的參考 與 呼叫
num=-5
a=b=c=abs
#參考
print(abs,a)
#呼叫
a(num)
b(-8.8)
c(7)
#函式名本質即變數,同一個函式物件可以被多個變數參考
def foo():#新建一個函式物件,并用foo這個變數名對其進行參考
pass
del foo#對函式物件的參考可以洗掉
#高階函式
def mycalucate(num,func):
return 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
callbackfunc(53,5,33)
7. BIFs中的高階函式
? filter
■核心點:對每個元素做過濾
語法:filter(function,list可迭代物件)
函式 f 的作用是對每個元素進行判斷,回傳 True或 False,
filter()根據判斷結果自動過濾掉不符合條件的元素,回傳由符合條件元素組成的新list,
? map
■核心點:對每個元素做映射
語法:map(function, list)
讓list的每一個元素依次呼叫function函式,并獲取回傳值存入一個新的list中,
? reduce
■核心點:兩兩傳給func
■Python 3.x中,reduce()函式已經被從全域名字空間里移除了,它和partical一樣被放置在 fucntools模塊中,使用前需要呼叫.
語法:from functools import reduce
reduce(function, list)
函式function必須包含兩個引數,optional可選,如果存在則表示初值為optional
reduce()對list的每個元素反復呼叫函式f,并回傳最終結果值,
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
myfilter(61)
l1=[1,61]
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)
# 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])
8. 匿名函式lambda
? 匿名函式lambda: 簡化函式
■使用場景:
《訓傳簡單結束 ,不需要專門定義函式
■特點:
□簡潔,同一行定義體+宣告,不用寫return
■定義:
□定義后,賦值給一個變數,做正常函式使用
□lambda關鍵字定義在高階函式的引數位上
■語法:
□lambda格式:lambda 接受n個引數:函式體,即: lambda(args1,args2, argsN):expression
#匿名函式--簡單的函式功能
#lambda語法:lambda 接受n個引數:函式體
print(type(lambda a,b:a**b ))
#定義
#函式體
#不用寫return
#使用1:作為正常函式使用,不推薦
foo=lambda x,y:x+y #不用寫return
#lambda
print(foo(5,6))
#使用2:lambda關鍵字定義在高階函式的引數位上
d1={'china':15,'India':9,'USA':2,'Japan':1.5} #排序key
sorted(d1.items(),key=lambda x:(x[0],x[1]))#按d1.items()第0個元素升序,國家名
# sorted(d1.items(),key=lambda x:(x[1]))#按d1.items()第1個元素升序,人口數
9. 閉包Closure
? 閉包的概念
■涉及嵌套函式時才有閉包問題
■內層函式參考了外層函式的變數(引數),然后回傳內層函式的情況,稱為閉包(Closure),
■這些外層空間中被參考的變數叫做這個函式的環境變數,
■環境變數和這個非全域函式一起構成了閉包,
? 閉包的特點:
■函式會記住外層函式的變數
? 閉包的實作:
10. 裝飾器Decorator
? 定義:
■以函式作引數并回傳一個替換函式的可執行函式
? 簡單理解:
■裝飾器的作用就是==為已存在的物件添加額外功能 ==
■為一個函式增加一個裝飾(用另一個函式裝飾)
■本質上就一個回傳函式的高階函式
? 應用:
■給函式動態增加功能(函式)
? 定義與使用:
@是python裝飾器的簡便寫法,也叫語法糖,裝飾器語法糖在要被包裹的函式前宣告,@后面的函式名,是包裹下邊函式的函式名extrafoo,
? 裝飾器在Python使用如此方便都要歸因于
Python的函式能像普通的物件一樣能作為引數傳遞給其他函式
可以被賦值給其他變數,可以作為回傳值,可以被定義在另外一個函式內,
#現有如下 三個函式
def foo1():
print ('this is foo1 function')
def foo2():
print ('this is foo2 function')
def foo3():
print ('this is foo3 function')
#現在想為每一個函式都添加一個列印當前時間的功能
#一種解決辦法是一個一個修改,在底部添加代碼,但問題是,太麻煩了~
import datetime
def foo1():
print ('this is foo1 function')
print(datetime.datetime.now())
def foo2():
print ('this is foo2 function')
print(datetime.datetime.now())
def foo3():
print ('this is foo3 function')
print(datetime.datetime.now())
#另一種辦法是,寫一個函式,負責列印時間,然后修改那三個函式
import datetime
def printtime():
print(datetime.datetime.now())
def foo1():
print ('this is foo1 function')
printtime()
def foo2():
print ('this is foo2 function')
printtime()
def foo3():
print ('this is foo3 function')
printtime()
#雖然不那么麻煩了,但還是每個函式都要修改,依舊很麻煩,
#法一:我們可以這樣解決
def foo1():
print ('this is foo1 function')
def foo2():
print ('this is foo2 function')
def foo3():
print ('this is foo3 function')
def extrafoo(func):
print(datetime.datetime.now())
return func
decorated=extrafoo(foo2)
decorated()
#這樣每次呼叫還是有點麻煩,要先寫一個函式接收,再呼叫,OK,再弄簡單一些
#法二:我們可以這樣解決: 已有功能foo1,現在想要加計時功能,再寫一個函式,利用裝飾器,
import datetime
def extrafoo(func):#func代表函式物件
def inner():
print('from inner to execute:',func.__name__)
print('the',func.__name__,'result:',func())#func()代表原始函式
print('extra:',datetime.datetime.now())#加計時功能,在原始函式后面加計時功能,
return inner
@extrafoo#裝飾器特性,被裝飾的函式定義之后立即運行,@extrafoo可以理解成decorated=extrafoo(foo1)以及decorated()
def foo1():
return 'this is foo1 function--'
#@是python裝飾器的簡便寫法,也叫語法糖
#裝飾器語法糖在要被包裹的函式前宣告,@后面的函式名,是包裹下邊函式的函式名extrafoo
#該語法糖省略了
#decorated=foo(test)
#decorated()
# 裝飾器在Python使用如此方便都要歸因于
# Python的函式能像普通的物件一樣能作為引數傳遞給其他函式
# 可以被賦值給其他變數,可以作為回傳值,可以被定義在另外一個函式內,
foo1()
11. 函式式編程Functional Programming
? 函式式編程思想:
■函式是第一等公民First Class
■函式式編程是一種編程范式,是如何撰寫程度的方法論, 把運算程序盡量變成一系列函式的呼叫,屬于結構化編程
? 特點:
■允許函式作為引數,傳入另一個函式
■回傳一個函式
? 理解:
■結合本章知識點,案例進行理解
本文的文字及圖片來源于網路加上自己的想法,僅供學習、交流使用,不具有任何商業用途,著作權歸原作者所有,如有問題請及時聯系我們以作處理,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/190364.html
標籤:Python
