標籤:python 裝飾器 迭代器
第一、
1、函數的嵌套的調用:在調用函數的過程中又調用了其他的函數。代碼簡潔、可讀性較高。
例1:
def foo():
print(‘from foo‘)
def bar():
print(‘from bar‘)
foo()
bar()
#結果:
from bar
from foo
例2:
def max2(x,y):
if x > y:
return x
else:
return y
def max4(a,b,c,d):
res1 = max2(a,b)
res2 = max2(res1,c)
res4 = max2(res2,d)
return res4
print(max4(1,4,2,5))
2、函數的嵌套定義:在一個函數的內部、又定義另外一個函數。
第二、
1、名稱空間:存放名字的地方、準確的說是存放名字和變數值綁定關係的地方。
python中的名稱空間有:
1、內建名稱空間:在py啟動的時候產生、存放一些python內建的名字。
print(),len(),max()……
2、全域名稱空間:在執行檔案時、檔案層級定義的名字。
x=1、
3、局部名稱空間:在執行檔案的過程中、如果調用了函數、則會產生該函數的局部名稱空間、用來存放該函數內定義的名字。在函數調用時生效,函數調用結束後失效。
三個名稱空間的載入順序:
內建-->全域-->局部
從上到下。
三個名稱空間的查詢順序:
局部-->全域-->內建
從下往上。
2、範圍:作用的應用範圍
全域範圍:全域有效、任何位置都能訪問得到。
全域包含:globals
1、內建名稱
2、全域名稱
例:
def f1():
def f2():
def f3():
print(max)
f3()
f2()
f1()
<built-in function max>
局部範圍:臨時有效、局部有效。
局部包含:locals
1、局部名稱
全域範圍的局部依然是全域範圍。
dir 查看對象下有哪些方法。
#global 關鍵字
global
x=1
def f1():
global x
x=2
f1()
print(x)
2
#不加global 也可以修改可變類型的資料
l = []
def f2():
l.append(‘f2‘)
f2()
print(l)l = []
def f2():
l.append(‘f2‘)
f2()
print(l)
[‘f2‘]
x=0
def f1():
x=3
def f2():
x=2
def f3():
global x
x=3
f3()
f2()
f1()
print(x)
3
x=0
def f1():
x=3
def f2():
x=2
def f3():
global x
x=3
f3()
print(x)
f2()
f1()
2
x=0
def f1():
x=3
def f2():
x=2
def f3():
nonlocal x
x=3
f3()
print(x)
f2()
f1()
3
#優先掌握:範圍關係在函數定義時就已經定義了,與調用的位置無關。需要回到原來定義函數的位置去找範圍關係
x= 1
def f1():
def f2():
print(x)
return f2
def foo(func):
x=100
func()
foo(f1())
1
#此處值為1是因為範圍的定義在上面。
3、閉包函數:閉合、包裹。
定義:
1、定義在函數內部的函數
2、包含對外部範圍名字的引用,而不是全域範圍名字得引用,那麼該內建函式就稱為閉包函數。
def f1():
x=2
def f2():
print(x)
return f2
res=f1()
res()
2
#此處的f2函數就是閉包函數、此時他不是獨立存在的他的外圍包一層範圍。
def deco():
x=123123
def wrapper():
print(x)
return wrapper
wrapper()
func=deco()
func()
123123
#查看外部變數
import requests
def index(url):
def get():
print(requests.get(url).text)
return get
python_web=index(‘http://www.python.org‘)
baidu_web=index(‘http://www.baidu.com‘)
print(python_web.__closure__)
(<cell at 0x0000007E65EA55E8: str object at 0x0000007E66035DF8>,)
import requests
def index(url):
def get():
print(requests.get(url).text)
return get
python_web=index(‘http://www.python.org‘)
baidu_web=index(‘http://www.baidu.com‘)
print(python_web.__closure__[0].cell_contents)
http://www.python.org
當閉包內建函式沒有被範圍包住的時候,他的範圍為None
4、為什麼要用裝飾器?
1、開發封閉原則:對擴充是開放的、對修改是封閉的。
裝飾器:目的為其他人添加新功能、
裝飾器可以是任意可調用對象、被裝飾的對象可以是任意可調用對象。
2、裝飾器需要遵循的原則:
2.1 不修改裝飾對象的原始碼
2.2 不修改被調用對象的功能
其目的就是滿足1和2條件添加新功能
例1:
import time
def index():
time.sleep(3)
print(‘welcome to index‘)
def home():
time.sleep(3)
print(‘welcome to home‘)
def timmer(func):
def wrapper():
start=time.time()
func()
stop=time.time()
print(‘run time is %s‘ %(stop-start))
return wrapper
index=timmer(index)
home=timmer(home)
index()
home()
簡寫裝飾器:
import time
def timmer(func):
def wrapper():
start=time.time()
func()
stop=time.time()
print(‘run time is %s‘ %(stop-start))
return wrapper
@timmer#裝飾器需要在調用的上面
def index():
time.sleep(3)
print(‘welcome to index‘)
@timmer#@等價 home=timmer(home)
def home():
time.sleep(3)
print(‘welcome to home‘)
index()
home()
#@裝飾器名、必須寫在被裝飾對象的正上方、而且是單獨一行
例2:、對被修飾對象加參數
import time
def timmer(func):
def wrepper(*args,**kwargs):
start=time.time()
func(*args,**kwargs)
stop=time.time()
print(‘run time is %s‘ %(stop-start))
return wrepper
@timmer
def index():
time.sleep(2)
print(‘welcome to index‘)
@timmer
def home(name):
time.sleep(2)
print(‘welcome to %s‘ %name)
index()
home(‘home‘)
例3:傳回值
#對被修飾對象加參數
import time
def timmer(func):
def wrepper(*args,**kwargs):
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print(‘run time is %s‘ %(stop-start))
return res
return wrepper
@timmer
def index():
time.sleep(2)
print(‘welcome to index‘)
return 123
@timmer
def home(name):
time.sleep(2)
print(‘welcome to %s‘ %name)
return 456
res=index()
print(res)
res1=home(‘home‘)
print(res1)
>>
welcome to index
run time is 2.00014328956604
123
welcome to home
run time is 2.0002007484436035
456
例3:用裝飾器實現使用者登入認證的功能
cust_dic={‘user‘:None}
def auth(func):
def auth_toke(*args,**kwargs):
if cust_dic[‘user‘]:
return func(*args, **kwargs)
user_inp = input(‘user>> ‘).strip()
pass_inp = input(‘pass>> ‘).strip()
with open(‘db‘,‘r‘,encoding=‘utf-8‘) as use_f:
use_list=eval(use_f.read())
if user_inp == use_list[0][‘user‘] and pass_inp == use_list[0][‘password‘]:
cust_dic[‘user‘] = user_inp
return func(*args,**kwargs)
else:
print(‘log in error‘)
return auth_toke
@auth
def access():
print(‘login sessfull‘)
@auth
def error(name):
print(‘welcome to is %s‘ %name)
access()
error(‘json‘)
>>:
user>> json
pass>> 123123
login sessfull
welcome to is json
#閉包函數只需要用到3層就能滿足一切函數的傳參。
#裝飾器補充
import time
def foo():
‘‘‘這是index函數‘‘‘
time.time()
print(‘access‘)
return 123
# print(help(foo))
print(foo.__doc__)
這是index函數
#多個裝飾器
誰在上面誰先生效。
5、迭代器:
迭代:重複的過程、每一次重複都是基於上一次的結果而來。
取出序列類型的元素就是迭代
例1:
l = [‘a‘,‘b‘,‘c‘,‘d‘]
count=0
while count < len(l):
print(l[count])
count+=1
>>
a
b
c
d
5.1、迭代器:取出非序列資料、不按索引。
5.2、可迭代對象:凡是對象有__iter__方法:對象.__iter__,該對象就是可迭代對象。
可迭代對象有:字串、列表、元組、字典。
例2:
dic={‘name‘:‘egon‘}
res=dic.__iter__()
print(res) #iterator 迭代器
例3:
dic={‘name‘:‘egon‘,‘age‘:11}
res=dic.__iter__()
print(next(res))
print(next(res)
>>
name
age
#StopIteration 提示迭代器沒有值了,應該停止了
迭代器本身也是可迭代的對象。
dic={‘name‘:‘egon‘,‘age‘:11}
# res=dic.__iter__()
res=iter(dic)
print(next(res))
print(next(res))
>>
name
age
#當迭代器遇到stopiteration的時候會停止運行。
s=‘hello‘
l=[‘a‘,‘b‘,‘c‘,‘d‘]
iter_l=iter(l)
while True:
try:
print(next(iter_l))
except StopIteration:
break
>>
a
b
c
d
6、迭代器對象:
6.1、有__iter__,執行結果仍然是迭代器本身
6.2、有__next__,執行一次取一個值
迭代器對象的優點:
1、提供統一的(不依賴於索引的)迭代方式
2、迭代器本身、比其他資料類型更省記憶體
3、迭代器可以存放無窮無盡個值。
例1、
with open(‘db‘,encoding=‘utf-8‘) as f:
print(next(f))
print(next(f))
print(next(f))
print(next(f))
>>
111111111111111111111
11111111111111
11111111111
1111111
迭代器缺點:
1、一次性的、只能往後不能回退、不如索引取值更靈活。
占記憶體大的環境不能用索引方式。
2、無法預知什麼時候結束、即無法預知長度。
for迴圈就是一個迭代器。
for迴圈的對象就是可迭代對象。
判斷一個對象是否是可迭代對象的方法就是?看該對象是否有iter方法。
檔案是迭代器。****
7、產生器
產生器:在函數內部包含yield關鍵字、那麼該函數的執行結果是產生器
產生器就是迭代器。
#yield的功能:
1、把函數的結果做產生器(以一種優雅的方式封裝__iter__,__next__)
2、函數暫停與繼續啟動並執行狀態是由yield
例1、手動實現rang函數。
def my_rang(start,stop):
while True:
if start == stop:
raise StopIteration
yield start
start+=1
for i in my_rang(1,3):
print(i)
7.1、yield 與 return的比較?
相同:都有傳回值的功能
不同:return只能返回一次、
例2、taif -f |grep 實現
import time
def tail(filepath):
with open(filepath,‘r‘) as f:
f.seek(0,2)
while True:
line = f.readline()
if line:
yield line
else:
time.sleep(0.2)
def grep(patten,lines):
for line in lines:
if patten in line:
print(line,end=‘‘)
grep(‘error‘,tail(‘db‘))
8、三元運算式:
為真時的結果 if 判定條件 else 為假時的結果
1 if 5>3 else 0
輸出為1、如果5大於3、否則輸出0
9、列表解析
根據已有列表,高效建立新列表的方式。
列表解析是Python迭代機制的一種應用,它常用於實現建立新的列表,因此用在[]中。
例1:傳統方式
l=[]
for n in range(11):
l.append(n)
print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
例2:列表解析
l=[ n for n in range(10)]
print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
例3:取出10內大於4的數字
傳統方法:
l=[]
for n in range(10):
if n >= 4:
l.append(n)
print(l)
[4, 5, 6, 7, 8, 9]
列表解析:
l=[ n for n in range(10) if n >=4 ]
print(l)
[4, 5, 6, 7, 8, 9]
10、產生器運算式:
產生器運算式並不真正的建立數字列表,而是返回一個產生器對象,此對象在每次計算出一個條目後,把這個條目"產生"(yield)出來。產生器運算式使用了"惰性計算"或稱作"延時求值"的機制。
序列過長,並且每次只需要擷取一個元素時,應該考慮產生器運算式而不是列表解析。
N=(i**2 for i in range(11))
print(N)
<generator object <genexpr> at 0x000000A5BE8A1D00>#此處返回的是一個產生器的地址
產生器取值通過next方法:
N=(i**2 for i in range(11))
# print(N)
print(next(N))
print(next(N))
print(next(N))
print(next(N))
0
1
4
9
產生器取值到元素遍曆完畢之後,拋出StopIteration
N=(i**2 for i in range(11))
# print(N)
while True:
try:
print(next(N))
except StopIteration:
break
本文出自 “男兒該自強” 部落格,請務必保留此出處http://nrgzq.blog.51cto.com/11885040/1951622
python 第四天