函數(shù)
簡(jiǎn)介
? 函數(shù)是組織好的,可重復(fù)使用的,用來(lái)實(shí)現(xiàn),單一或相關(guān)聯(lián)的功能
? 函數(shù)能提高模塊的利用行,和代碼的重復(fù)利用率以及冗余,其實(shí)你已經(jīng)使用了很多的Python函數(shù),比如print()。
? 但是你也可以自己創(chuàng)建函數(shù),這種叫做自定義函數(shù)
函數(shù)規(guī)則
- 函數(shù)代碼塊必須以def 關(guān)鍵字開(kāi)頭,后面為函數(shù)標(biāo)識(shí)符名以及()
- 任何傳入的參數(shù)和自定變量必須放在圓括號(hào)中間。圓括號(hào)之間可以用來(lái)定義參數(shù)
- 函數(shù)的第一行語(yǔ)句可以選擇性的使用注釋字符來(lái)表明函數(shù)的作用及說(shuō)明
- 函數(shù)的內(nèi)容以冒號(hào)起始,并且必須縮進(jìn)
- return [表達(dá)式] 結(jié)束函數(shù),選擇性的返回一個(gè)值給調(diào)用該函數(shù)方。不帶表達(dá)式的函數(shù)默認(rèn)會(huì)返回
None
語(yǔ)法
#語(yǔ)法 def functionname( parameters ): "函數(shù)_文檔字符串" function_suite return [expression] #實(shí)例 def printme( str ): "打印傳入的字符串到標(biāo)準(zhǔn)顯示設(shè)備上" print(str) return
默認(rèn)情況下,參數(shù)值和參數(shù)名稱是按函數(shù)聲明中定義的順序匹配起來(lái)的。
函數(shù)調(diào)用
- 定義一個(gè)函數(shù)只能給函數(shù)一個(gè)名稱,指定函數(shù)里包含的參數(shù),和代碼塊結(jié)構(gòu)
- 函數(shù)基本結(jié)構(gòu)完成以后,你可以通過(guò)另一個(gè)函數(shù)調(diào)用執(zhí)行,也可以直接從python提示符執(zhí)行
#!/usr/bin/python # -*- coding: UTF-8 -*- # 定義函數(shù) def printme( str ): #打印任何傳入的字符串 print(str); return; # 調(diào)用函數(shù) printme("hello world"); #傳參 printme("再次調(diào)用同一函數(shù)");
參數(shù)傳遞
- 函數(shù)已經(jīng)講清楚了,但是函數(shù)不夠完美,比如一個(gè)例子,函數(shù)里定義一個(gè)變量a='hello world' 調(diào)用函數(shù)我們只能返回一個(gè)不能變化的字符串,我們?nèi)绻氪蛴e的字符串就不行了
例子:
接上面函數(shù)調(diào)用的代碼
我們告訴printme每次打印我傳進(jìn)來(lái)的東西,這個(gè)過(guò)程叫做 傳遞參數(shù) , 簡(jiǎn)稱
傳參
實(shí)參和形參
? 參數(shù)還有分別:
? 我們調(diào)用函數(shù)時(shí)傳遞的這個(gè)
hello world
被稱為 實(shí)際參數(shù) ,因?yàn)檫@個(gè)是我們實(shí)際交給函數(shù)處理的內(nèi)容,簡(jiǎn)稱 實(shí)參
? 定義函數(shù)時(shí),括號(hào)里的str,只是一個(gè)變量的名字,被稱為 形式參數(shù) ,因?yàn)樵诤瘮?shù)定義時(shí)它只是一個(gè)形式,表示這里需要一個(gè)參數(shù),檢查 形參? 傳遞多個(gè)參數(shù):
? 參數(shù)可以傳遞多個(gè),用逗號(hào)
,
分開(kāi)實(shí)參角度
- 按照位置傳參
def mymax(x,y): #此時(shí)x=10,y=20 the_max = x if x > y else y > return the_max ma = mymax(10,20) print(ma)
? 2.按照關(guān)鍵字傳參
def mymax(x,y): #此時(shí)x = 20,y = 10 print(x,y) the_max = x if x > y else y return the_max ma = mymax(y = 10,x = 20) print(ma)
? 3.位置、關(guān)鍵字形式混著用
def mymax(x,y): #此時(shí)x = 10,y = 20 print(x,y) the_max = x if x > y else y return the_max ma = mymax(10,y = 20) print(ma)
? 正確用法:
- 問(wèn)題一:位置參數(shù)必須在關(guān)鍵字參數(shù)的前面
- 問(wèn)題二:對(duì)于一個(gè)形參只能賦值一次
?
形參角度
位置參數(shù)必須傳值
def mymax(x,y): #此時(shí)x = 10,y = 20 print(x,y) the_max = x if x > y else y return the_max #調(diào)用mymax不傳遞參數(shù) ma = mymax() print(ma) #結(jié)果 TypeError: mymax() missing 2 required positional arguments: 'x' and 'y'
默認(rèn)參數(shù)
- 正常使用
作用:可以將變化最小的值設(shè)置成默認(rèn)參數(shù)
- 默認(rèn)參數(shù)的定義
def stu_info(name,sex = "male"): """打印學(xué)生信息函數(shù),由于班中大部分學(xué)生都是男生, 所以設(shè)置默認(rèn)參數(shù)sex的默認(rèn)值為'male' """ print(name,sex) stu_info('alex') stu_info('eva','female')
- 參數(shù)陷阱:默認(rèn)參數(shù)是一個(gè)可變數(shù)據(jù)類型
def defult_param(a,l = []): l.append(a) print(l) defult_param('alex') defult_param('egon')
動(dòng)態(tài)參數(shù)
? 按位置傳值多余的參數(shù)都由args統(tǒng)一接收,保存成一個(gè)元組的形式
def mysum(*args): the_sum = 0 for i in args: the_sum+=i return the_sum the_sum = mysum(1,2,3,4) print(the_sum)
? 按默認(rèn)參數(shù)傳入多個(gè)參數(shù),保存成為字典格式
def stu_info(**kwargs): print(kwargs) print(kwargs['name'],kwargs['sex']) stu_info(name = 'alex',sex = 'male')
命名空間和作用域
- 命名空間的本質(zhì):存放名字與值的綁定關(guān)系
命名空間一共分為三種: 全局命名空間 內(nèi)置命名空間 局部命名空間
內(nèi)置命名空間
存放了python解釋器為我們提供的名字:input print str list tuple 拿過(guò)來(lái)就可以用的函數(shù)方法三種命名空間直接的加載和順序
? 加載順序:內(nèi)置命名空間(程序運(yùn)行前加載) --> 全局命名空間(程序運(yùn)行中:從上到下加載) --> 局部命名空間(程序運(yùn)行中,調(diào)用時(shí)才會(huì)加載)
取值
? 在局部調(diào)用:局部命名空間->全局命名空間->內(nèi)置命名空間
x = 1 def f(x): print(x) print(10)
? 在全局調(diào)用:全局命名空間->內(nèi)置命名空間
#全局x x = 1 def f(x): print(x) f(10) print(x) #全局max print(max)
- 作用域
作用域就是作用范圍,按照生效范圍可以分為全局作用域和局部作用域。
全局作用域:包含 內(nèi)置名稱空間、全局名稱空間 ,在整個(gè)文件的任意位置都能被引用、全局有效
局部作用域:局部名稱空間,只能在局部范圍 內(nèi) 生效
globals和locals方法
print(globals()) print(locals()) # 在局部調(diào)用globals和locals def func(): a = 12 b = 20 print(locals()) print(globals()) func() # 關(guān)鍵字global a = 10 def func(): global a a = 20 print(a) func() print(a)
函數(shù)小結(jié)
-
定義函數(shù)的規(guī)則:
1.定義:def 關(guān)鍵詞開(kāi)頭,空格之后接函數(shù)名稱和圓括號(hào)()。
2.參數(shù):圓括號(hào)用來(lái)接收參數(shù)。若傳入多個(gè)參數(shù),參數(shù)之間用逗號(hào)分割。 參數(shù)可以定義多個(gè),也可以不定義。 參數(shù)有很多種,如果涉及到多種參數(shù)的定義,應(yīng)始終遵循位置參數(shù)、*args、默認(rèn)參數(shù)、**kwargs順序定義。 如上述定義過(guò)程中某參數(shù)類型缺省,其他參數(shù)依舊遵循上述排序
3.注釋:函數(shù)的第一行語(yǔ)句應(yīng)該添加注釋。
4.函數(shù)體:函數(shù)內(nèi)容以冒號(hào)起始,并且縮進(jìn)。
5.返回值:return [表達(dá)式] 結(jié)束函數(shù)。不帶表達(dá)式的return相當(dāng)于返回 Nonedef 函數(shù)名(參數(shù)1,參數(shù)2,*args,默認(rèn)參數(shù),**kwargs):
"""注釋:函數(shù)功能和參數(shù)說(shuō)明"""
函數(shù)體
……
return 返回值 -
調(diào)用函數(shù)的規(guī)則:
1.函數(shù)名()
函數(shù)名后面+圓括號(hào)就是函數(shù)的調(diào)用。
2.參數(shù):
圓括號(hào)用來(lái)接收參數(shù)。
若傳入多個(gè)參數(shù):
應(yīng)按先位置傳值,再按關(guān)鍵字傳值
具體的傳入順序應(yīng)按照函數(shù)定義的參數(shù)情況而定
3.返回值
如果函數(shù)有返回值,還應(yīng)該定義“變量”接收返回值
如果返回值有多個(gè),也可以用多個(gè)變量來(lái)接收,變量數(shù)應(yīng)和返回值數(shù)目一致無(wú)返回值的情況:
函數(shù)名()有返回值的情況:
變量 = 函數(shù)名()多個(gè)變量接收多返回值:
變量1,變量2,... = 函數(shù)名() -
命名空間:
一共有三種命名空間從大范圍到小范圍的順序:內(nèi)置命名空間、全局命名空間、局部命名空間
作用域(包括函數(shù)的作用域鏈): 小范圍的可以用大范圍的但是大范圍的不能用小范圍的范圍從大到小
高階函數(shù)
-
函數(shù)的本質(zhì)
函數(shù)名的本質(zhì)實(shí)際上就是函數(shù)的內(nèi)存地址
- 可以被引用
def func():
print('in func')
f = func
f()
print(f)
- 可以被當(dāng)作容器的元素
def f1():
print('f1')
def f2():
print('f2')
l = [f1,f2]
d = {'f1':f1,'f2':f2}
l[0]()
d['f1']()
-
閉包函數(shù)
def func(): name = 'eva' def inner(): print(name)
閉包函數(shù)定義 :內(nèi)部函數(shù)包含對(duì)外部作用域而非全局作用域名字的引用,該內(nèi)部函數(shù)稱為閉包函數(shù)
函數(shù)內(nèi)部定義的函數(shù)稱為內(nèi)部函數(shù),這樣就不能拿到函數(shù)內(nèi)部的變量和函數(shù),只能返回
#輸出的__closure__有cell元素 :是閉包函數(shù) def func(): name = 'eva' def inner(): print(name) print(inner.__closure__) return inner f = func() f() #輸出的__closure__為None :不是閉包函數(shù) name = 'egon' def func2(): def inner(): print(name) print(inner.__closure__) return inner f2 = func2() f2()
裝飾器
python裝飾器是利用函數(shù)特性的閉包完成的,
開(kāi)放封閉原則 :面向?qū)ο缶幊毯诵脑瓌t,軟件實(shí)體應(yīng)該是可以擴(kuò)展的,而不可修改的。也就是說(shuō)對(duì)擴(kuò)展時(shí)開(kāi)放的,而對(duì)代碼本體修改是封閉的
- 開(kāi)放原則:對(duì)擴(kuò)展時(shí)開(kāi)放的
- 封閉原則:對(duì)修改時(shí)封閉的
? 裝飾器的作用 :裝飾器是可以在不改動(dòng)原有代碼功能的基礎(chǔ)上,可以擴(kuò)展的功能。正是對(duì)開(kāi)放封閉原則的完美體現(xiàn)。
? 工作原理 :依然在調(diào)用原有功能代碼,但是能實(shí)現(xiàn)調(diào)用裝飾器函數(shù)里的功能
def index(): '''這是一個(gè)主頁(yè)信息''' print('from index') print(index.__doc__) #查看函數(shù)注釋的方法 print(index.__name__) #查看函數(shù)名的方法 print(inner.__closure__) #輸出的__closure__有cell元素 :是閉包函數(shù)
? 標(biāo)準(zhǔn)格式 :
from functools import wraps #已經(jīng)開(kāi)發(fā)好的裝飾器模塊 def deco(func): # 裝飾器函數(shù) #@wraps(func) # 加在最內(nèi)層函數(shù)正上方 def wrapper(*args,**kwargs): # 加一堆參數(shù) *args,**kwargs接受 return func(*args,**kwargs) return wrapper #返回內(nèi)部函數(shù)的名字(注意) @deco #==> index = deco(index) #語(yǔ)法糖 @裝飾器函數(shù)名,下面必須是被裝飾的函數(shù) def index(): '''哈哈哈哈''' print('from index') print(index.__doc__) print(index.__name__)
固定格式 :
使用情況 :
? 在已經(jīng)寫(xiě)好的發(fā)版的程序功能基礎(chǔ)上,需要對(duì)一個(gè)函數(shù)執(zhí)行前后增加功能的時(shí)候
? 有的時(shí)候也會(huì)寫(xiě)好一些裝飾器,裝在需要裝飾的函數(shù)上
生成器
我們知道的迭代器有兩種:一種是調(diào)用方法直接返回的,一種是可迭代對(duì)象通過(guò)執(zhí)行iter方法得到的,迭代器有的好處是可以節(jié)省內(nèi)存。
如果在某些情況下,我們也需要節(jié)省內(nèi)存,就只能自己寫(xiě)。我們自己寫(xiě)的這個(gè)能實(shí)現(xiàn)迭代器功能的東西就叫生成器。
Python中提供的生成器:
1.生成器函數(shù):常規(guī)函數(shù)定義,但是,使用yield語(yǔ)句而不是return語(yǔ)句返回結(jié)果。yield語(yǔ)句一次返回一個(gè)結(jié)果,在每個(gè)結(jié)果中間,掛起函數(shù)的狀態(tài),以便下次重它離開(kāi)的地方繼續(xù)執(zhí)行
2.生成器表達(dá)式:類似于列表推導(dǎo),但是,生成器返回按需產(chǎn)生結(jié)果的一個(gè)對(duì)象,而不是一次構(gòu)建一個(gè)結(jié)果列表
生成器Generator:
本質(zhì):迭代器(所以自帶了__iter__方法和__next__方法,不需要我們?nèi)?shí)現(xiàn))
特點(diǎn):惰性運(yùn)算,開(kāi)發(fā)者自定義
生成器函數(shù):
一個(gè)包含yield關(guān)鍵字的函數(shù)就是一個(gè)生成器函數(shù)。yield可以為我們從函數(shù)中返回值,但是yield又不同于return,return的執(zhí)行意味著程序的結(jié)束,調(diào)用生成器函數(shù)不會(huì)得到返回的具體的值,而是得到一個(gè)可迭代的對(duì)象。每一次獲取這個(gè)可迭代對(duì)象的值,就能推動(dòng)函數(shù)的執(zhí)行,獲取新的返回值。直到函數(shù)執(zhí)行結(jié)束。
示例代碼:
import time
def genrator_fun1():
a = 1
print('現(xiàn)在定義了a變量')
yield a
b = 2
print('現(xiàn)在又定義了b變量')
yield b
g1 = genrator_fun1()
print('g1 : ',g1) #打印g1可以發(fā)現(xiàn)g1就是一個(gè)生成器
print('-'*20) #我是華麗的分割線
print(next(g1))
time.sleep(1) #sleep一秒看清執(zhí)行過(guò)程
print(next(g1))
生成器有什么好處呢?就是不會(huì)一下子在內(nèi)存中生成太多數(shù)據(jù)
文件監(jiān)聽(tīng)例子
import time
def tail(filename):
f = open(filename)
f.seek(0, 2) #從文件末尾算起
while True:
line = f.readline() # 讀取文件中新的文本行
if not line:
time.sleep(0.1)
continue
yield line
tail_g = tail('tmp')
for line in tail_g:
print(line)
列表推導(dǎo)式和生成器表達(dá)式
#老男孩由于峰哥的強(qiáng)勢(shì)加盟很快走上了上市之路,alex思來(lái)想去決定下幾個(gè)雞蛋來(lái)報(bào)答峰哥
egg_list=['雞蛋%s' %i for i in range(10)] #列表解析
#峰哥瞅著alex下的一筐雞蛋,捂住了鼻子,說(shuō)了句:哥,你還是給我只母雞吧,我自己回家下
laomuji=('雞蛋%s' %i for i in range(10))#生成器表達(dá)式
print(laomuji)
print(next(laomuji)) #next本質(zhì)就是調(diào)用__next__
print(laomuji.__next__())
print(next(laomuji))
總結(jié):
1.把列表解析的[]換成()得到的就是生成器表達(dá)式
2.列表解析與生成器表達(dá)式都是一種便利的編程方式,只不過(guò)生成器表達(dá)式更節(jié)省內(nèi)存
3.Python不但使用迭代器協(xié)議,讓for循環(huán)變得更加通用。大部分內(nèi)置函數(shù),也是使用迭代器協(xié)議訪問(wèn)對(duì)象的。例如, sum函數(shù)是Python的內(nèi)置函數(shù),該函數(shù)使用迭代器協(xié)議訪問(wèn)對(duì)象,而生成器實(shí)現(xiàn)了迭代器協(xié)議,所以,我們可以直接這樣計(jì)算一系列值的和:
sum(x ** 2 for x in range(4))
而不用多此一舉的先構(gòu)造一個(gè)列表:
sum([x ** 2 for x in range(4)])
更多詳情請(qǐng)看:https://www.cnblogs.com/Eva-J/articles/7276796.html
匿名函數(shù)
匿名函數(shù)
匿名函數(shù):為了解決那些功能很簡(jiǎn)單的需求而設(shè)計(jì)的一句話函數(shù)
#這段代碼
def calc(n):
return n**n
print(calc(10))
#換成匿名函數(shù)
calc = lambda n:n**n
print(calc(10))
上面是我們對(duì)calc這個(gè)匿名函數(shù)的分析,下面給出了一個(gè)關(guān)于匿名函數(shù)格式的說(shuō)明
函數(shù)名 = lambda 參數(shù) :返回值
#參數(shù)可以有多個(gè),用逗號(hào)隔開(kāi)
#匿名函數(shù)不管邏輯多復(fù)雜,只能寫(xiě)一行,且邏輯執(zhí)行結(jié)束后的內(nèi)容就是返回值
#返回值和正常的函數(shù)一樣可以是任意數(shù)據(jù)類型
我們可以看出,匿名函數(shù)并不是真的不能有名字。
匿名函數(shù)的調(diào)用和正常的調(diào)用也沒(méi)有什么分別。 就是 函數(shù)名(參數(shù)) 就可以了~~~
練一練:
請(qǐng)把以下函數(shù)變成匿名函數(shù)
def add(x,y):
return x+y
上面是匿名函數(shù)的函數(shù)用法。除此之外,匿名函數(shù)也不是浪得虛名,它真的可以匿名。在和其他功能函數(shù)合作的時(shí)候
l=[3,2,100,999,213,1111,31121,333]
print(max(l))
dic={'k1':10,'k2':100,'k3':30}
print(max(dic))
print(dic[max(dic,key=lambda k:dic[k])])
res = map(lambda x:x**2,[1,5,7,4,8])
for i in res:
print(i)
輸出
1
25
49
16
64
res = filter(lambda x:x>10,[5,8,11,9,15])
for i in res:
print(i)
輸出
11
15
面試題練一練
現(xiàn)有兩個(gè)元組(('a'),('b')),(('c'),('d')),請(qǐng)使用python中匿名函數(shù)生成列表[{'a':'c'},{'b':'d'}]
#答案一
test = lambda t1,t2 :[{i:j} for i,j in zip(t1,t2)]
print(test(t1,t2))
#答案二
print(list(map(lambda t:{t[0]:t[1]},zip(t1,t2))))
#還可以這樣寫(xiě)
print([{i:j} for i,j in zip(t1,t2)])
1.下面程序的輸出結(jié)果是:
d = lambda p:p*2
t = lambda p:p*3
x = 2
x = d(x)
x = t(x)
x = d(x)
print x
2.現(xiàn)有兩元組(('a'),('b')),(('c'),('d')),請(qǐng)使用python中匿名函數(shù)生成列表[{'a':'c'},{'b':'d'}]
3.以下代碼的輸出是什么?請(qǐng)給出答案并解釋。
def multipliers():
return [lambda x:i*x for i in range(4)]
print([m(2) for m in multipliers()])
請(qǐng)修改multipliers的定義來(lái)產(chǎn)生期望的結(jié)果。
遞歸函數(shù)
Python內(nèi)部:最大的遞歸深度為1000次
內(nèi)置函數(shù)
# dir可以查看一個(gè)數(shù)據(jù)可以調(diào)用哪些方法 也可以通過(guò)某一個(gè)方法是不是在結(jié)果中,從而判斷
dir()
callable()
print()
sep # 分隔符
ent # 結(jié)束符
file # 寫(xiě)入文件,文件句柄
eval()
exec()
open()
input()
id()
sum min max # 都支持接受iter 可迭代對(duì)象
ord # 字符找到Ascii碼的位置
chr # Ascii碼的位置找到字符
repr # 打印某個(gè)變量的值的值得時(shí)候,更便于區(qū)分類型
reversed # 反轉(zhuǎn) 本身不變,返回的是個(gè)迭代器
filter # 返回值為迭代器 查找
map # 返回值為迭代器
enumerate #枚舉函數(shù) enumerate(iterable,1)
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
