1. 程式人生 > >4)裝飾器、叠代器、生成器以及內置函數

4)裝飾器、叠代器、生成器以及內置函數

裝飾器;叠代器;生成器以及內置函數

裝飾器、叠代器、生成器以及內置函數

裝飾器:

原函數前後增加功能,切不改變函數的原本使用方式

import time
def wrapper(f):
def inner():
start = time.time()
f()
end = time.time()
print('執行效率為%s'%(end-start))
return inner

@wrapper
def func():
print('this is func')
time.sleep(0.3)
func()

import time
def wrapper(f):
def inner(*args,**kwargs):#帶參數的裝飾器
start = time.time()
f(*args,**kwargs)
end = time.time()
print('執行效率為%s'%(end-start))
return inner

@wrapper
def func(a,b):
print(a,b)
print('this is func')
time.sleep(0.3)
func(111,222)

再加一個666

import time
def wrapper(f):
def inner(*args,**kwargs):#帶參數的裝飾器
start = time.time()
set = f(*args,**kwargs)
end = time.time()
print('執行效率為%s'%(end-start))
return set
return inner

@wrapper
def func(a,b):
print(a,b)
print('this is func')

time.sleep(0.3)
return 666
print(func(111,222))

進階需求:

情況一:

500個函數

設計裝飾器,確認是否生效

import time
FLAG = True
def outer(flag):
def wrapper(f):
def inner(*args,**kwargs):#帶參數的裝飾器
if flag == True:

start = time.time()
set = f(*args,**kwargs)
end = time.time()
print('執行效率為%s'%(end-start))
else:
set = f(*args,**kwargs)
return set
return inner
return wrapper

@outer(FLAG)
def func(a,b):
print(a,b)
print('this is func')
time.sleep(0.3)
return 666
print(func(111,222))

情況二:

登陸,紀錄日誌

login_info = {'alex':False}

def login(func):
def inner(name):
if login_info[name] !=True:
user = input('>>>user')
pwd = input('>>pwd')
if user =='alex' and pwd =='alex3714':
login_info[name] = True
if login_info[name] == True:
ret = func(name)
return ret
return inner


def wrapper1(func): #f
def inner1():
print('wrapper1 ,before func')
func() # f
print('wrapper1 ,after func')
return inner1

def wrapper2(func): # inner1
def inner2():
print('wrapper2 ,before func')
func() # inner1
print('wrapper2 ,after func')
return inner2

@wrapper2
@wrapper1
def f():
print('in f')

f()

技術分享圖片

import time
login_info = {'alex':False}
def login(func):
def inner(name):
if login_info[name] !=True:
user = input('>>>user')
pwd = input('>>pwd')
if user =='alex' and pwd =='alex3714':
login_info[name] = True
if login_info[name] == True:
ret = func(name)
return ret
return inner

def timmer(f):
def inner(*args,**kwargs):
start = time.time()
ret = f(*args,**kwargs)
end = time.time()
print('執行效率%s'%(end-start))
return ret
return inner
@login
@timmer
def index(name):
print('歡迎%s考到博客園'%name)
time.sleep(0.3)
@login
@timmer
def manager(name):
print('歡迎%s考到博客園管理頁面'%name)
time.sleep(0.3)
index('alex')
manager('alex')

叠代器和生成器

叠代器:

凡是可以使用for循環取值的都是可叠代的

#從列表、字典中取值
# index索引
#for 凡是通過for循環取值的都是可叠代的

可叠代協議:

內部有__iter__方法的都是可叠代的

叠代器協議:

內部有__iter____next__方法的都是叠代器

創建叠代器使用__iter__() 或者 iter()

dir()可以查看使用的內置方法

l = [1,2,3]
ll = iter(l)
print(ll.__next__())
print(ll.__next__())

l = [1,2,3]
lst_iter = iter(l) #lst_iter = iter(l) == lst_iter = [1,2,3].__iter__()

while True:
print(next(lst_iter)) #lst_iter.__next__()

l = [1,2,3]
ll = iter(l)
while True:

print(next(ll)) #報錯了

沒有就會出錯

l = [1,2,3]
lst_iter = iter(l) #lst_iter = iter(l) == lst_iter = [1,2,3].__iter__()

while True:
try:
print(next(lst_iter)) #lst_iter.__next__()
except StopIteration:
break

總結:

什麽是可叠代:內部有__iter__

什麽是叠代器:叠代器=iter(可叠代的) 自帶__next__方法

節省內存

Range()

from collections import Iterable,Iterator
print(range(10000))
print(isinstance(range(10000),Iterable)) #True
print(isinstance(repr(10000),Iterator)) #False


Python2range會生成一個列表,將用來存儲生成所有的值

技術分享圖片

Python3range不管要多少,都不會生成實際的值

在使用的時候在生成

for i in range(1000):

節省內存,速度快

特性:惰性運算

生成器:

自己寫的叠代器就是生成器

兩種自己寫生成器的機制:

生成器函數:

凡是帶有yield的函數是個生成器

def func():
print('****')
yield 1
g = func()
next(g)

def func():
print('****')
yield 1
print('^^^^')
yield 2
g = func()
print('___',next(g))
print('===',next(g))

Yield 記錄當前所在位置,等待下一次next來觸發函數的狀態

想要執行要next

def cloth_g(name):
for i in range(name):
yield 'choth_g%s'%i
g = cloth_g(10)
next(g)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))

使用生成器監聽文件輸入:

import time
def lister_file():
with open('userinfo') as f1:
while True:
line = f1.readline()
if line.strip():
yield line.strip()
time.sleep(0.3)

g = lister_file()
for i in g:
print(i)
if i =='error':
break

技術分享圖片

Send 關鍵字

在執行next的時候,傳遞一個參數給生成器函數的內部

1)

def func():
print(1111)
yield 1
print(2222)
yield 2
print(3333)
yield 3

func()
next(func())
next(func())

2) :

def func():
print(1111)
yield 1
print(2222)
yield 2
print(3333)
yield 3

g = func()
ret = next(g)
print(ret)

技術分享圖片

3) :

def func():
print(1111)
ret1 = yield 1
print(2222,'ret1:',ret1)
ret2 = yield 2
print(3333,'ret2:',ret2)
yield 3

g = func()
ret = next(g)
print(g.send('alex'))
print(g.send('lxf'))

向生成器中傳遞值,有個激活過程,第一次必須用next觸發這個生成器

def average():
sum_money = 0 #總錢數
day = 0 #天數
avg = 0 #平均的錢
while True:
money = yield avg
sum_money += money
day +=1
avg = sum_money/day
g = average()
next(g)
print(g.send(200))
print(g.send(300))

技術分享圖片

例子:

預激生成器:

就是吧要激活的next放到一個裝飾器當中,比如說有多個程序需要激活的話,可以這樣做,為了簡便,如果要是就一個程序的話就沒有必要了

yield from

def generator_func():
for i in range(5):
yield i
for j in 'hello':
yield j
g = generator_func()

#如何取值

#1,next、隨時可以停止,最後會報錯
print(next(g))
print(next(g))

#2,for循環、從頭到尾遍歷一次,不遇到break、return不停止
for i in g:
print(i)


#3,list、tuple
print(list(g))#一次性所有的都轉換了,如果多太占內存
print(g)

上面的內容可以進行替換成如下:

def generator_func():
yield from range(5)
yield from 'hello'
# for i in range(5):
# yield i
# for j in 'hello':
# yield j
g = generator_func()
for i in g:
print(i)

總結:

1)生辰器函數,是我們python程序員實現叠代器的一種手段

2)主要特征是在函數中含有yield

3)調用一個生成器函數,不會執行這個函數中的代碼,只是會獲得一個生成器代碼

4)只有從生辰器中取值的時候,才會執行函數內部的代碼,且每獲取一個數據才執行的到這個數據的代碼

5)獲取數據方式,nextsend 循環 數據類型的強制轉化

6)Yield 返回值的簡便方法,如果本身就是循環一個可叠代,且要把可叠代數據中的每一個元素都返回,可以用yield from

7)使用send的時候,在生成器創造出來之後需要進行預激活,這一步可以使用裝飾器完成

8)生成器特點:節省內存、惰性運算

9)生成器用來解決內存和程序功能之間的解耦


列表推到試:表現為 []

new = []
for i in range(10):
new.append(i**2)
print(new)


#上面的復雜不好
print([i **2 for i in range(10)])#列表推到式

ll = [1,2,3,-5,6,20,-7]#求每個數的余數
print([ i%2 for i in ll])

ll = [1,2,3,-5,6,20,-7]
print([i for i in ll if i %2 ==0])

#30以內搜友能被3整除的數
print([i for i in range(30) if i % 3 ==0])
#30以內搜友能被3整除的數的平方
print([i**2 for i in range(30) if i % 3 ==0])

#:找到嵌套列表中名字含有兩個‘e’的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
# for i in names:
# for j in i: #復雜不好
# if j.count('e') ==2:
# print(j)

print( [j for i in names for j in i if j.count('e') ==2])

生成器表達式:表現為 ()

技術分享圖片

練習題:

技術分享圖片

自定義函數:

自己定義的【name = uuu’】

內置函數:

拿過來直接用的,python直接封裝好的

Printlenmaxmindir

叠代器/生成器相關的:

Rangenext iter

作用域相關的:

Globals

Locals

其他:

Input

Print:九九乘法表
for i in range(1,10):
for j in range(1,i+1):
print('%s*%s=%2s'%(i,j,i*j),end=' ')
print()

print(1,2,3,4,5,sep=';',end=' ')#1;2;3;4;5
print(1,2,3,4,5,sep=';',end='')#1;2;3;4;5

進度條

import time
for i in range(0,101,2):
time.sleep(0.1)
char_num = i//2
per_str = '\r%s%% : %s\n' % (i, '*' * char_num) if i ==100 else'\r%s%% : %s'%(i,'*'*char_num)
print(per_str,end='')

import time
for i in range(0,101,2):
time.sleep(0.1)
char_num = i//2
if i ==100:
per_str = '\r%s%% : %s\n' %(i,'*'* char_num)
else:
per_str='\r%s%%: %s'%(i,'*' *char_num)
print(per_str,end='')

Hash

對可hash的數據類型進行hash之後會的到一個數字
在一次程序的執行過程中,對相同的可哈希變量,哈希之後的結果永遠相同
在一次程序的執行過程中,對不相同的可哈希變量,哈希之後的結果幾乎是不相同的
hash字典底層的存儲和set 集合的去重機制都有關

Id():

Open

Import

Help

Callable:可調用

def func():
pass
a = 1
print(callable(func))#True
print(callable(a))#False

Dir: 查看這一個變量的所有方法、屬性

Bin:進制


print(bin(10))#二進制
print(oct(10))#十進制
print(hex(10))#十六進制


abs計算數字絕對值

print(abs(4))
print(abs(-4))

divmod:商余函數

print(divmod(10,2))#(5, 0)
print(divmod(7,3))#(2, 1)
print(divmod(9,7))#(1, 2)

Round:小數精確

print(round(3.1415926,4))#3.1416 小數精確四舍五入

Pow:平方

print(pow(2,3))#8
print(pow(3,2))#9

Sum:求和

print(sum([1,2,3,4,5]))

Min:計算最小值

print(min([1,2,3,4,5]))#1
print(min([1,2,3,4,5]))#1
print(min(1,-2,3,-4,key=abs))#1


def func(num):
return num%2
print(min(-2,3,-4,key=func))

Max:和min一樣

List

Tuper

Reverse:反轉

Reversed()
ret = [1,2,3,4,5]
ret1 = reversed(ret)
ret2 = reversed((1,2,3,4,5))
print(ret)#[1, 2, 3, 4, 5]
print(list(ret1))#[5, 4, 3, 2, 1]
print(list(ret2))#[5, 4, 3, 2, 1]

Str

Format

Bytes

Ord

print(ord('a'))#小寫的a-z 97+26 大寫的A-Z 65+26

Chr

print(chr(97))#a


Repr:
print(repr(1))#1
print(repr('1'))#'1'

Enumerate:枚舉函數

l = ['蘋果','香蕉','橘子']
for index,i in enumerate(l,1):
print(index,i)

l = ['蘋果','香蕉','橘子']
ret = enumerate(l,1)
for i in ret:
print(i[0],i[1])

沒啥用:

技術分享圖片

Zip:拉鏈方法:

ss =zip([1,2,3,4],('a','b','c','d'))
for i in ss:
print(i)

Filter用於過濾不需要的元素


ll = [1,4,6,7,12,17]
def func(num):
if num %2 ==0:return True
for i in filter(func,ll):
print(i)

g=(i for i in ll if i%2 ==0)


l = ['test',None,'','str', ' ','END']
def func(item):
if item and item.strip():return True
for i in filter(func,l):
print(i)

Map

def func(num):
return num**2
for i in map(func,range(10)):print(i)

Sorted:排序功能


l = [1,-4,-2,3,-5,6,5]
l.sort(key=abs)
print(l)


l = [1,-4,-2,3,-5,6,5]
new = sorted(l,reverse=True)
print(new)


l = [[1,2,],[3,4,5,6],(7,),'123']
print(sorted(l,key=len))

eval

eval('print(123)')

exec

exec ('print(123)')#123
eval('print(123)')#123

print(eval('1+2-3*20/(2+3)')) -9.0
print(exec('1+2-3*20/(2+3)'))# none

匿名函數:

Lambda表達式:

邏輯比較簡單
1):

add = lambda a,b: a+b
print(add(1,2))



2):

def func(num):
return num**2
for i in map(func,range(10)):print(i)



for i in map(lambda num : num**2,range(10)):print(i)

3):
def func(num):
return num%2
print(max(-2,3,-4,key=func))


print(max(-2,3,-4,key=lambda num:num%2))

遞歸:

技術分享圖片

技術分享圖片

技術分享圖片

遞歸自己調用自己

需要有一個停止的條件

技術分享圖片


4)裝飾器、叠代器、生成器以及內置函數