標籤:auth 建立 tuple consumer 元組 空間 預設 use 寫法
一、裝飾器
1、定義:本質是函數,裝飾其他函數就是為其他函數添加附件功能。
2、原則:
a.不能修改被裝飾的函數的原始碼;
b.不能修改被裝飾的函數的調用方式;
執行個體:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#Author:ye
import time
#裝飾器
def time_cha(func):#func等於test
time_start = time.time()
func()#此時func()相當於test()
time.sleep(2)
time_stop = time.time()
print("the time cha is :%s" % (time_stop - time_start))
#主函數
def test():
print("*")
time.sleep(1)
print("*")
time.sleep(1)
print("in the test")
#單獨調用主函數
test()
#將裝飾器套用在主函數上
time_cha(test)#此方式改變了主函數的調用方式
3、實現裝飾器的知識儲備:
a.函數即“變數”
b.高階函數
b1.把一個函數名當做實參傳遞給另外一個函數(在不修改被裝飾函數的前提下,增加其功能)
執行個體:
def test1():#此函數時原始碼
print("in the test1")
def test2(func):#此函數時裝飾器
print("in the test2")
print(func)#列印test1的記憶體位址
func()#這裡相當於test1()
test1()
test2(test1)#將test1這個函數名作為實參傳遞給test2,這樣實現了高階函數
b2.傳回值中包含函數名(不改變函數(原始碼)的調用方式)
執行個體:
def test1():#原始碼
print("in the test1")
def test2(func):#裝飾器
print("in the test2")
func()
return test1#通過return,把函數名作為傳回值
test1 = test2(test1)#此處是test1函數名的記憶體位址
test1()#執行test1函數
c.嵌套函數
def test1():#第一層函數
print("in the test1")
def test2():#第二層函數
print("in the test2")
test2()#第一層函數執行時,調用第二層函數
test1()#執行第一層函數
4、裝飾器的案例分析:
案例背景:首先定義兩個模組,歐美專區和河南專區,兩個專區的使用前提是需要登入。
步驟一:首先實現兩個專區的免登入訪問;
步驟二:定義登入模組,然後以登入模組做為裝飾器,裝飾在歐美專區和河南專區上
步驟三:當調用到兩個專區模組時,再進行登入驗證,不能調用之前就進行驗證(此處涉及到了嵌套函數的使用)
status = False #初始化登入狀態,false表示未登入,true表示已登入
def login(func): #定義登入模組(裝飾器函數)
def inner(): #定義嵌套函數
_uername = "zhangye" #定義使用者資料
global status #將函數內變數全域化
if status ==False: #根據狀態判斷是否需要登入
username = input("請輸入使用者名稱:")
if username == _uername:
print("welcome...")
status = True #登入成功後,將預設狀態由false轉化為true
if status == True:
print(func)
func()
return inner #未調用時,不進行驗證,只返回一個第二層的函數名(驗證函式的函數名)
@login #還未到真正調用函數的地方,所以此處不需要進行登入驗證,只返回第二層的函數名即可。
def america():
print("*****歐美專區*****")
@login #還未到真正調用驗證函式的地方,所以此處不需要進行登入驗證,只返回第二層函數名即可。
def henan():
print("*****河南專區*****")
america() #調用時,執行第二層函數。因為上面已經拿到了第二層的函數名
henan() #調用時,執行第二層函數。因為上面已經拿到了第二層的函數名
二、產生器
通過列表產生式,我們可以直接建立一個列表。但是,受到記憶體限制,列表容量肯定是有限的。而且,建立一個包含100萬個元素的列表,不僅佔用很大的儲存空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。
所以,如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的過程中不斷推算出後續的元素呢?這樣就不必建立完整的list,從而節省大量的空間。在Python中,這種一邊迴圈一邊計算的機制,稱為產生器:generator。
要建立一個generator,有很多種方法。第一種方法很簡單,只要把一個列表產生式的[]改成(),就建立了一個generator:
執行個體一:
data = [1,2,3,4,5,6,7,8,9,]
#列表產生式(裝逼的寫法)
data = [i*2 if i > 4 else i for i in data]
print(data)
==》[1, 2, 3, 4, 10, 12, 14, 16, 18]
#清單產生器(資料用到的時候才產生)
data2 = (i*2 if i > 4 else i for i in data)
print(data2)
==》<generator object <genexpr> at 0x000002797C151DB0>
小結:產生器只有在調用時,才會產生相應的資料。
執行個體二、
import time
#定義消費者模型函數
def consumer(name): print("%s 準備吃包子啦!" %name)
while True:
baozi = yield
print("包子[%s]來了,被[%s]吃了!" % (baozi,name))
#定義生產者模型函數
def producer(name):
c_a = consumer("A")
c_b = consumer("B")
c_a.__next__()
c_b.__next__()
print("老子開始準備做包子了!")
for i in range(10):
time.sleep(1)
print("做了2個包子!")
c_a.send(i)
c_b.send(i)
producer("alex")
三、迭代器
我們知道,可以直接作用於for迴圈的資料類型有以下幾種:
一類是集合資料類型:如list,tuple,dict,set,str等;
一類是 generator,包括產生器和帶yield的generator函數。
這些可以直接作用於for迴圈的對象統稱為可迭代對象,Iterable
可以使用isinstance()判斷一個對象是否是Iterable對象:
from collections import Iterable
#判斷字串是否可迭代
data = "abc"
print(isinstance(data,Iterable)) #===》True
#判斷列表是否可迭代
data = [1,2,3]
print(isinstance(data,Iterable)) #===》True
#判斷字典是否可迭代
data = {1:"ye",2:"zhang",3:"alex"}
print(isinstance(data,Iterable)) #===》True
#判斷元組是否可迭代
data = (1,2,3)
print(isinstance(data,Iterable)) #===》True
注1:可以被next()函數調用並不斷返回下一個值的對象稱為迭代器:Iterator。
注2:字典、集合、元組、字串等都是可迭代對象,但是不是迭代器。但是可以通過iter()函數獲得一個迭代器。
python的重重之器(產生器、迭代器、裝飾器)