函數:
內置函數(鏈接)
一.函數初始
默認參數的陷阱
默認參數若是可變的數據類型,他始終使用的是一個內存地址。
def func1(x,l1=[]):
l1.append(x)
return l1
ret = func1(1)
ret1 = func1(100)
return是函數結束的標志,函數內可以寫多個return,但只執行一次
無return 返回None
只寫return,后面不寫其他內容,也會返回None
return 逗號分隔多個值 返回元組
返回多個值,用多個變量接收
a,b,c,d = ret_demo2()
形參即變量名,實參即變量值
函數即變量 函數的賦值 f = func
命名關鍵字參數:*后定義的參數,必須被傳值(有默認值的除外),且必須按照關鍵字實參的形式傳遞
可以保證,傳入的參數中一定包含某些關鍵字
def foo(位置形參,*args,默認參數,**kwargs):
函數體
return 返回值
動態參數
溢出的位置參數值以元祖形式賦給args ,溢出的關鍵字參數以字典的形式賦給kwargs
*args,**kwargs
函數定義時:*聚合 *args:實參里面所有的位置參數。
**kwargs:實參里面所有的關鍵字參數。
函數的調用時:* 打散。
形參的順序:位置參數,*args,默認參數,**kwargs。
二.函數進階
存放名字與值的關系’的空間起了一個名字-------命名空間。
全局名稱空間。
臨時名稱空間。
內置名稱空間。
全局作用域: 全局名稱空間,內置名稱空間。
局部作用域: 局部名稱空間。
取值順序:就近原則,從小到大。
加載順序:加載的是名稱空間。
global nonlocal
globals() locals() 以字典形式返回模塊全部全局變量和局部變量
全局作用域:包含內置名稱空間、全局名稱空間
局部作用域:局部名稱空間,只能在局部范圍內生效
- 函數名的本質。
函數名本質上就是函數的內存地址。
1.可以被引用
2.可以被當作容器類型的元素
3.可以當作函數的參數和返回值
第一類對象(first-class object)指
1.可在運行期創建
2.可用作函數參數或返回值
3.可存入變量的實體。
- 一句話,函數名能當普通變量用
嵌套函數:
匿名函數:使用一次就釋放
- lambda x,y:x**y
- 匿名函數主要是和其它函數搭配使用
高階函數:
變量可以指向函數,函數的參數能接收變量,那么一個函數就可以接收另一個函數作為參數,這種函數就稱之為高階函數。
只需滿足以下任意一個條件,即是高階函數
- 接受一個或多個函數作為輸入
- return 返回另外一個函數
def add(x,y,f):
return f(x) + f(y)
遞歸
在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。
查看遞歸次數
n = 1
def func(x):
print(x)
x+=1
func(x)
func(n)
def calc(n):
v = int(n/2)
print(v)
if v > 0:
calc(v)
print(n)
calc(10)
遞歸特性:
- 必須有一個明確的結束條件
- 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
- 遞歸效率不高,遞歸層次過多會導致棧溢出()
應用:二分查找
閉包原理
閉包函數:內部函數包含對外部作用域而非全劇作用域變量的引用,該內部函數稱為閉包函數,并返回.
閉包的意義:返回的函數對象,不僅僅是一個函數對象,在該函數外還包裹了一層作用域,這使得,該函數無論在何處調用,優先使用自己外層包裹的作用域
應用領域:延遲計算(原來我們是傳參,現在我們是包起來)
閉包作用:
當程序執行時,遇到了函數執行,他會在內存中開辟一個空間,局部名稱空間,
如果這個函數內部形成了閉包,
那么他就不會隨著函數的結束而消失。
name = 'alex'
def wraaper():
def inner():
print(name)
print(inner.__closure__) # None不是閉包函數
inner()
return inner
wraaper()
name = 'hqs'
def wraaper(n):
n = 'alex'
def inner():
print(n)
print(inner.__closure__) # cell at 0x000002AD93BF76D8 --> 是閉包函數
inner()
return inner
wraaper(name)
可迭代對象:Iterable
: str list dict,tuple,set,range()
對象內部含有iter方法就是可迭代對象.
print('__iter__' in dir(對象)) #返回True.False
from collections import Iterable #判斷是否是可迭代對象
from collections import Iterator #判斷是否是迭代器
print(isinstance('對象',Iterable)) # True/False
print(isinstance('對象',Iterator)) # True/False
可迭代對象滿足可迭代協議。
迭代器:Iterator
對象內部含有__iter__方法且含有__next__方法就是迭代器.
文件本身就是迭代器對象
迭代器的缺點:
- 取值麻煩,只能一個一個取,只能往后取,
- 并且是一次性的,無法用len獲取長度
可迭代對象不能取值,迭代器是可以取值的。
可迭代對象 --->(轉化成)迭代器
迭代器=可迭代對象.iter() #等于 迭代器=iter(可迭代對象) #轉化
1,將可迭代對象轉化成迭代器。
2,調用next方法取值。
3,利用異常處理停止報錯。
模式for循環
迭代器 = 可迭代對象.__iter__()
while 1:
try:
print(迭代器.__next__())
except StopIteration:
break
裝飾器:
開放封閉原則:
軟件上線后,對修改源代碼是封閉的,對功能的擴展功能是開放的。
方案:裝飾器
原則:
* 1,不修改原代碼
* 2,不修改調用方式
目的:
遵循1和2的基礎上拓展新功能
裝飾器:
裝飾為被裝飾對象添加新功能
含義:
裝飾器即在不修改被裝飾對象源代碼與調用方式的前提下,為被裝飾對象添加新功能
裝飾器 ==》函數
被裝飾的對象 ==》函數
time.time() 獲取當前時間(s)
生成器:就是自己python用代碼寫的迭代器,生成器的本質就是迭代器。
generator是可迭代對象 , 可用for循環和next()
用以下兩種方式構建一個生成器:
- 1,通過生成器函數。
- 2,生成器表達式。
生成器函數 vs 迭代器:
- 迭代器是需要可迭代對象進行轉化。可迭代對象非常占內存。
- 生成器直接創建,不需要轉化,從本質就節省內存。
- send 與next一樣,也是對生成器取值(執行一個yield)的方法。
- send 可以給上一個yield 傳值。
- 第一次取值永遠都是next。
- 最后一個yield 永遠也得不到send傳的值。
- yield 將值返回給 生成器對象.next()
迭代器.next() 相當于 next(迭代器)
把函數做成迭代器
* 對比return,可以返回多次值,掛起函數的運行狀態
創建生成器:如下
def func1(): #生成器函數
print(1)
count = (yield 6)
print(count)
count1 = (yield 7)
print(count1)
yield 8
g = func1() #調用生成器函數創建生成器對象
print(next(g))
print(g.send('alex'))
print(g.send('alex'))
def cloth2(n):
for i in range(1,n+1):
yield '衣服%s號' % i
g = cloth2(10000)
for i in range(50):
print(g.__next__()) #停在50的位置
for i in range(50): #從51開始
print(g.__next__())
列表推導式
- 循環模式 : [變量(加工后的變量) for 變量 in iterable]
- 篩選模式 : [變量(加工后的變量) for 變量 in iterable if 條件]
優點:一行解決,方便。
缺點:容易著迷,不易排錯,不能超過三次循環。
列表推導式不能解決所有列表的問題,所以不要太刻意用。
生成器表達式:
將列表推導式的 [] 換成() 即可。
三元表達式:ret = 'true' if 1 == 1 else 'false'