閉包,裝飾器,迭代器,生成器

閉包f2.__closure__(判斷是否爲閉包,是返回地址,否返回None)
定義:內部函數引用了外部函數的變量(非全局)
def f1(b):
    def f2():
        print(b) # 這樣也是閉包
閉包的常用狀態:
def f1(b):
def f2():
print(b)
return f2
ff = f1('hhh')
ff() # 輸出 hhh
裝飾器
作用:在不改變函數的調用方式的情況下,給函數的前後添加新的功能
先來一個萬能模板:
defwrapper(func):
    definner(*args,**kwargs):
    """被裝飾函數執行之前要添加的代碼"""
    ret = func(*args,**kwargs)
    """被裝飾函數執行之後要添加的代碼"""
    return  ret
return  inner
①#從最簡單的裝飾器
deftimmer(qqx):#timmer是裝飾器的名字,傳入的參數就是被裝飾的函數
    definner():#在裝飾器中需要定義一個內部函數
        print('調用func之前')
        qqx() #被裝飾的函數,並且要執行
        print('調用func之後')
    returninner#將內部函數的名字返回
@timmer#語法糖 func = timmer(func)
deffunc():
    print('公司好老闆好同事好')
func()
②# 完整的裝飾-萬能的裝飾
deftimmer(qqxing):#timmer是裝飾器的名字,傳入的參數就是被裝飾的函數
    definner(*args,**kwargs):#在裝飾器中需要定義一個內部函數
        print('調用func之前')
        ret = qqxing(*args,**kwargs)#被裝飾的函數,並且要執行
        print('調用func之後')
    return ret
return inner#將內部函數的名字返回
@timmer#語法糖 func = timmer(func)
deffunc(name):
    print('%s的公司好老闆好同事好'%(name))
        return 1111111111
    ret = func('哈哈')
print('result : %s'%ret)
### 調用func之前
### 俊傑的公司好老闆好同事好
### 調用func之後
### result : 1111111111
#裝飾器:開放封閉原則
用裝飾器實現,訪問art或者dar函數,登陸一次之後,無需再次登錄
flag = False
deflogin(func):
    definner(*args,**kwargs):
    globalflag
    ifflag ==False:
    username = input('用戶名:')
    password = input('密碼:')
    if username =='alex'and password =='somebody':
        print('登錄成功')
        flag = True
    if flag ==True:
        ret = func(*args,**kwargs)
    return ret
return inner
@login
defart():
    print('歡迎來到文章頁')
@login
defdar():
    print('歡迎來到日記頁')
art()
dar()
deflog(func):
    definner(*args,**kwargs):
        f =open('geci','a',encoding='utf-8')
f.write('你要調用%s函數了\n'%func.__name__)
        f.close()
    ret = func(*args,**kwargs)
    return ret
return inner
@log
deff1():
    print('f1')
@log
deff2():
    print('f2')
f1()
f2() ### 成功將'你要調用f1函數了你要調用f2函數了'寫入’geci'文件
擴充:
r: 可讀 文本操作模式
w: 可寫 文本操作模式
rb: 直接操作二進制
wb: 直接操作二進制
當拿到的是純文字,就用文本操作的模式
當你拿到的是字節,就用二進制操作模式
迭代器:
__iter__
內部含有__iter__方法的數據類型,就是可迭代的 ------可迭代協議
print(dir(l)) # 打印關於l的方法
迭代器:iterator
1、一個容器,我們從這個容器當中一個接着一個把值取出來的過程就是迭代的過程。
2、用法:可迭代的 == 可迭代對象 Python一切皆對象
①
print(dir(l)) # 打印關於l的方法
print(dir(lst_iter))
print(set(dir(lst_iter)) - set(dir(l))) # 兩個用法的差集
list_iter.__next__() # 迭代器比可迭代的多一個__next__方法 
②
l = ['ha','hei','hou']
ret = l.__iter__()
print(ret.__next__()) # ha
print(ret.__next__()) # hei
print(ret.__next__()) # hou
3、
可迭代的必須 含有__iter__方法 # 可迭代協議
迭代器比可迭代的多一個__naxt__方法
迭代器:包含__naxt__,__iter__方法 # 迭代器協議
包含__naxt__方法的可迭代對象就是迭代器 ,迭代器是可迭代的一部分
4、如何判斷一個變量是不是迭代器或者可迭代的
①
print('__iter__' in dir([1,2,3,4])) # True
print('__next__' in dir([1,2,3,4])) # False
②
from collections import Iterable # 可迭代
from collections import Iterator # 迭代器
print(isinstance([1,2,3,4],Iterable)) # True
str_iter = 'abc'.__iter__() 
print(isinstance(str_iter,Iterator)) # True
print(isinstance('abc',Iterator)) # False
5、迭代器的特點:①惰性運算 ② 不可逆不可重複 ③ 節省內存
6、用while寫for 循環:
l = [1,2,3,4,5]
l_iter = l.__iter__()
while True:
    try:
        print(l_ter.__next__())
    except StopIteration:
        break
7、目前我們已知的可迭代的都是Python提供給我們的:
range() f(文件) enumerate()
for 循環是讓我們更簡單的使用迭代器,用迭代器取值就不需要關心索引或者key的問題了。
生成器:
一、
生成器本身就是迭代器
生成器函數和普通函數之間的區別
生成器函數中含有 yield 關鍵字
生成器函數調用的時候不會立即執行,而是返回一個生成器。
二、
def g_func():
    print('I am here.')
    yield 1
    print('I am OK!')
    yield 2
    g = g_func() # 若只到這一步,什麼都不打印
    print(g.__next__()) # 若沒有 print ,只有g.__next__則只打印’ I am here.‘
### 結果:I am here. \n 1
print(g.__next__()) # 都打
三、
衣服問題:
def cloth():
    for i in range(1,1000001):
    yield '衣服%s'%i
g = cloth
for i in range(50): # 取出50件
    print(g.__next__())
四、
send(和__next__一樣,更高級的就是可以傳值)
send 之前必須有一個__next__方法
def func():
print('*********')
a = yield 5
yield 10
g = func
num = g.__next__()
print(num)
num2 = g.send('jieshenziai')
print(num2)
從哪一個yield開始接着執行,就把一個值傳給那個yield。
send 不能做第一個觸發器,send前必須有一個yield。
②文件追蹤(最後一行)需要保存底下下才顯示:
def tail():
f = open('文件',encoding='utf-8')
f.seek(0,2)     (光標移動到最後)
while True:
line = f.readline()
if line:
yield line
import time
time.sleep(0,1)
g = tail()
for i in g:
print(i.strip())
num2 = g.send('惹人感慨')
③下面是一個比較6的 計算移動平均值。
def average():
total = 0.0
count = 0
average = None
while True:
term = yield average
total += term
count += 1
average = total / count
g_avg = average()
g_avg.__next__()
print(g_avg.send(10))
print(g_avg.send(30))
print(g_avg.send(50))
五、生成器的預激裝飾器
def init(func):
    def inner(*args,**kwargs):
        ret = func(*args,**kwargs)
        ret.__next__()
        return ret
    return inner
因爲,send之前總是要 next 所以,就有了這個預激裝飾器
六、小栗子輸出 A,B,C,D
①方法
def func():
    a = 'AB'
    b = 'CD'
    for i in a:
        yield i
    for i in b:
        yield i
func()
g = func()
for i in g:
    print(i)
②方法
def func():
    a = 'AB'
    b = 'CD'
    yield from a       # 這是py3 中特有的
    yield from b
func()
g = func()
for i in g:
    print(i)
七、觸發執行的方式:
next(send):執行幾次那幾個數據,取完會報錯
for循環:每次取一個,取完爲止,不會報錯
八、生成器表達式
列表推導式:
y = range(30) 
x = [i*i for i in y ]
生成器表達式:(這個比較好,因爲它每次就取一個)
g = (i*i for i in y )
for i in g:
print(i)
小栗子:(雞蛋和雞的關係)
l = ['雞蛋%s'%i for i in range(10)]
    print(l)
laomuji = ('雞蛋%s'%i for i in range(10))
for egg in laomuji:
    print(egg)
小結:
惰性運算:不取值就不計算,且每一個值只能被取一次,取完爲止
可迭代對象:
擁有__iter__方法
特點:惰性運算
例如:range(),str,list,tuple,dict,set
迭代器:
擁有__iter__和__next__方法
例:iter(range()),iter(str),iter(list),iter(tuple),iter(dict),iter(set),
reversed(list_o),map(func,list_o),filter(func,list_o),file_o
生成器Generator:
本質:迭代器,所以擁有__iter__和__next__方法
特點:惰性運算,開發者自定義
使用生成器的優點:
1、延遲計算,一次返回一個結果。不會一次生成所有結果,對大數據量處理,非常有用。
2、提高代碼可讀性


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章