程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

python - 閉包與裝飾器

編輯:Python

目錄

一、python的閉包

示例1:閉包

示例2:形成閉包的條件

示例3:形成閉包以後,閉包函數會得到一個非空的__closure__屬性

示例4:賦值引用閉包和直接調用外函數的區別

二、裝飾器

示例1:統計函數執行時間

示例2:寫一個統計函數運行時間的裝飾器

示例3:什麼是裝飾器

示例4:用裝飾器實現權限控制

示例5:保留元數據

示例6:用類實現裝飾器

示例7:裝飾類


一、python的閉包

示例1:閉包

def outer(x):
a = 300
def inner():
print(f"兩數之和{x + a}")
return inner
d = outer(10)
d()

 變量解析原則:

        LEGB 原則

         local當前局部變量  enclosing function 閉包空間  global全局  buildins 內建模塊
         理論上來說,函數執行完了以後,變量a會釋放
         但是這個時候還有inner函數在引用他們,這個時候就形成了閉包

示例2:形成閉包的條件

形成閉包條件:(缺一不可)
1、必須有一個內嵌函數
2、內函數必須引用外函數的變量
3、外函數必須返回內函數

示例3:形成閉包以後,閉包函數會得到一個非空的__closure__屬性

def outer(x):
a = 300
def inner():
print(f"兩數之和{x + a}")
return inner
d = outer(10)
d()
# 閉包形成後,閉包函數會得到一個非空的__closure__屬性
print(dir(d))
print(d.__closure__)
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-閉包和裝飾器/01、閉包.py
兩數之和310
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
(<cell at 0x0000015CD0A9FE80: int object at 0x0000015CD09993B0>, <cell at 0x0000015CD09417F0: int object at 0x0000015CBEE46A50>)
Process finished with exit code 0

示例4:賦值引用閉包和直接調用外函數的區別

雖然代碼一樣,但是每次調用外函數都會重新執行,創建一個新的tmp_list和inner
匿名變量,都是統一放到匿名空間的,所以地址一樣

tmp_list = []
def outer():
tmp_list = []
def inner(name):
tmp_list.append(1)
print(f"{name} -- {tmp_list}")
return inner
d1 = outer()
d2 = outer()
d1("d1")
d2("d2")
# 雖然代碼一樣,但是每次調用外函數都會重新執行,創建一個新的tmp_list和inner
print(id(d1), id(d2))
# 匿名變量,都是統一放到匿名空間的,所以地址一樣
print(id(outer()), id(outer()))
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-閉包和裝飾器/01、閉包.py
d1 -- [1]
d2 -- [1]
2138501753296 2138501753440
2138501753584 2138501753584

二、裝飾器

示例1:統計函數執行時間

時間戳:

        從1970年1月1日的0點0分0秒到現在所經歷的秒數

import time
def func1():
time.sleep(2)
print("func1....")
# 時間戳
# 從1970年1月1日的0點0分0秒到現在所經歷的秒數
t1 = time.time()
func1()
t2 = time.time()
print(f"函數執行時間{t2 - t1}")
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-閉包和裝飾器/02、裝飾器.py
func1....
函數執行時間2.0112464427948

示例2:寫一個統計函數運行時間的裝飾器

@ :修飾符

import time
def runtime(func):
print("this is runtime")
def inner():
start = time.time()
func()
end = time.time()
print(f"函數執行花了{end - start}s")
return inner
@runtime # @修飾符去使用裝飾器 # runtime(func2)
def func2():
time.sleep(2)
print("func2....")
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-閉包和裝飾器/02、裝飾器.py
this is runtime
func2....
函數執行花了2.0134215354919434s

示例3:什麼是裝飾器

裝飾器是一種模式,它的本質是閉包,
他在不改變函數或者類的源代碼的基礎上
為函數或類添加功能
 裝飾器有什麼用
• 你可以考慮在裝飾器中置入通用功能的代碼來降低程序復雜度。例如,可以用裝飾器來:
• 引入日志
• 增加計時邏輯來檢測性能
• 給函數加入事務的能力
• 權限控制

示例4:用裝飾器實現權限控制

# 裝飾器實現權限控制
def login_required(func):
def inner(*args, **kwargs):
if username == "root":
print("歡迎")
result = func(*args, **kwargs)
return result
else:
return "權限不夠"
return inner
# 可以應用多個裝飾器,但是要注意順序
# 從最上面的裝飾器的內涵式開始執行
@login_required
def add(a, b):
time.sleep(2)
return a + b
username = input("請輸入用戶名:")
result = add(1, 2)
print(result)
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-閉包和裝飾器/02、裝飾器.py
請輸入用戶名:root
歡迎
3

示例5:保留元數據

import time
def runtime(func):
# 保留傳遞進來的函數的元數據,將它的元數據賦值給inner
@functools.wraps(func)
def inner(*args, **kwargs): # 讓裝飾器更加通用
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"函數 {func.__name__} 執行花了:{end -start}s")
return result
return inner
#
# a = runtime("name")
# add = a(add)
@runtime # add = runtime(add)
def add(a, b):
print("this is add ")
time.sleep(1)
return a+b
add(1, 2)
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-閉包和裝飾器/03、裝飾器參數.py
this is add
函數 add 執行花了:1.0147972106933594s
import functools
import time
def deco(name):
def runtime(func):
#保留傳遞進來的函數的元數據,將它的元數據賦值給inner
@functools.wraps(func)
def inner(*args, **kwargs): #讓裝飾器更加通用
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"函數執行花了{end -start}s")
print(f"name is {name}")
return result
return inner
return runtime
# runtime = deco(name="sanle")
#func1 = runtime(func1)
@deco(name="sanle")
def func1():
time.sleep(3)
print("this is func1")
func1()

示例6:用類實現裝飾器

import time
class A:
def __init__(self, func):
self.func = func
def __call__(self, func):
def deco(*args, **kwargs):
start = time.time()
print("this is call")
result = func(*args, **kwargs)
end = time.time()
print(f"函數執行時間{end - start}")
return result
return deco
@A("name")
def func1():
time.sleep(2)
print("i am func1....")
func1()

示例7:裝飾類

def outer(cls):
def inner(*args, **kwargs):
print(f"class name is:{cls.__name__}")
return cls(*args, **kwargs)
return inner
@outer
class A:
def __init__(self, name):
self.name = name
print(type(A))
m = A("sc")
print(m.name)
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-閉包和裝飾器/05、裝飾類.py
<class 'function'>
class name is:A
sc


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved