一阻逮、裝飾器介紹
裝飾器也是一個(gè)函數(shù)粱快,它是讓其他函數(shù)在不改變變動(dòng)的前提下增加額外的功能。
裝飾器是一個(gè)閉包叔扼,把一個(gè)函數(shù)當(dāng)作參數(shù)返回一個(gè)替代版的函數(shù)事哭,本質(zhì)是一個(gè)返回函數(shù)的函數(shù)(即返回值為函數(shù)對(duì)象)。
python3支持用@符號(hào)直接將裝飾器應(yīng)用到函數(shù)瓜富。
裝飾器工作場(chǎng)景:插入日志鳍咱、性能測(cè)試、事務(wù)處理等等与柑。
函數(shù)被裝飾器裝飾過后谤辜,此函數(shù)的屬性均已發(fā)生變化蓄坏,如名稱變?yōu)檠b飾器的名稱。
1. 簡(jiǎn)單的裝飾器
1.1. 被裝飾的函數(shù)不帶參數(shù)
"""入門裝飾器:函數(shù)功能不帶參數(shù)"""
def my_decorator(func):
def inner():
print("**********")
print("要添加的功能代碼")
func()
return inner
# script1()函數(shù)調(diào)用裝飾器的第一種方法
def script1():
print("測(cè)試")
runScript1 = my_decorator(script1) # 運(yùn)行script()函數(shù)的同時(shí)添加有my_decorator()函數(shù)的功能
runScript1()
# script1()函數(shù)調(diào)用裝飾器的第二種方法:使用@符號(hào)丑念,簡(jiǎn)單明了
@my_decorator
def script1():
print("測(cè)試")
script1()
1.2. 被裝飾的函數(shù)帶參數(shù)
可變參數(shù)args和關(guān)鍵字參數(shù)*kwargs添加函數(shù)通用的裝飾器
"""入門裝飾器:函數(shù)帶參數(shù)"""
def my_decorator(func):
def inner(*args, **kwargs): # 可變參數(shù)*args和關(guān)鍵字參數(shù)**kwargs
print("**********")
print("要添加的功能代碼")
func(*args, **kwargs)
return inner
# script2()函數(shù)調(diào)用裝飾器的第一種方法:了解即可
def script2(arg):
print("測(cè)試:%s" % arg)
runScript2 = my_decorator(script2)
runScript2("aaa")
# script2()函數(shù)調(diào)用裝飾器的第二種方法:使用@符號(hào)涡戳,目前使用此方法
@my_decorator
def script2(arg):
print("測(cè)試:%s" % arg)
script2("aaa")
2. 裝飾器帶參數(shù)
"""裝飾器:裝飾器帶參數(shù)"""
def my_decorator(name):
def outer(func):
def inner(*args, **kwargs):
print("********")
print("添加帶裝飾器參數(shù)%s的功能代碼" % self.name)
func(*args, **kwargs)
return inner
return outer
@my_decorator(name='settings')
def script3(arg):
print("測(cè)試----%s" % arg)
script3("bbb")
3. 基于類封裝的裝飾器
__call __()方法是將實(shí)例成為一個(gè)可調(diào)用對(duì)象(即callable對(duì)象),同時(shí)不影響實(shí)例的構(gòu)造脯倚,但可以改變實(shí)例的內(nèi)部值渔彰。
3.1. 基于類封裝的不帶參數(shù)裝飾器
通過類封裝裝飾器的實(shí)現(xiàn)方法:先通過構(gòu)造函數(shù)__init __()傳入函數(shù);再通過__call __方法重載推正,并返回一個(gè)函數(shù)恍涂。
"""基于類封裝的不帶參數(shù)裝飾器"""
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("********")
print("要添加的功能代碼")
return self.func(*args, **kwargs)
@MyDecorator
def script4(arg):
print("測(cè)試----%s" % arg)
script4("ccc")
3.2. 基于類封裝的帶參數(shù)裝飾器
通過類封裝裝飾器的實(shí)現(xiàn)方法:先通過構(gòu)造函數(shù)__init __()傳入裝飾器參數(shù);再通過__call __方法傳入被裝飾的函數(shù)舔稀,并返回一個(gè)函數(shù)乳丰。
"""基于類封裝的帶參數(shù)裝飾器"""
class MyDecorator:
def __init__(self, name):
self.name = name
def __call__(self, func):
def inner(*args, **kwargs):
print("********")
print("添加帶裝飾器參數(shù)%s的功能代碼" % self.name)
func(*args, **kwargs)
return inner
@MyDecorator(name="settings")
def script4(arg):
print("測(cè)試----%s" % arg)
script4("ddd")
二、常用的內(nèi)置裝飾器
1. @property裝飾器
- @property:將一個(gè)方法變?yōu)閷傩哉{(diào)用内贮。
未添加裝飾器@property時(shí)产园,函數(shù)類型是一個(gè)方法:<class 'method'>
添加裝飾器@property時(shí),函數(shù)類型是返回值的類型:如夜郁,<class 'str'> - property對(duì)象的setter方法:表示給屬性添加設(shè)置功能什燕,即可修改屬性值。
若未添加設(shè)置屬性竞端,就設(shè)置新值屎即,則會(huì)引發(fā)錯(cuò)誤AttributeError: can't set attribute。 - property對(duì)象的deleter方法:表示給屬性添加刪除功能
若添加刪除屬性事富,就刪除屬性則會(huì)引發(fā)錯(cuò)誤AttributeError: can't delete attribute技俐。
"""@property裝飾器"""
class Test1:
def __init__(self, name):
self.__name = name
@property # 將函數(shù)由方法變?yōu)閷傩? def get_name(self):
return self.__name
@get_name.setter # 添加設(shè)置屬性
def get_name(self, value):
if not isinstance(value, str):
raise TypeError("參數(shù)應(yīng)為字符串類型,但實(shí)際是%s類型" % type(value))
else:
self.__name = value
@get_name.deleter # 添加刪除屬性
def get_name(self):
del self.__name
test1 = Test1("launcher")
# 獲取get_name類型
print(type(test1.get_name)) # 結(jié)果: <class 'str'>
# 獲取get_name屬性值
print(test1.get_name) # 結(jié)果:launcher
# 給get_name屬性設(shè)置新值:添加設(shè)置屬性需使用裝飾器@property的setter函數(shù)统台;
test1.get_name = "賦新值"
print(test1.get_name) # 結(jié)果:賦新值
# 刪除get_name屬性:刪除屬性需使用裝飾器@property的deleter函數(shù)雕擂;
del test1.get_name
print(test1.get_name) # 結(jié)果:報(bào)錯(cuò)(AttributeError: 'Test1' object has no attribute '_Test1__name'),表示刪除屬性成功
"""@property實(shí)例:加減法運(yùn)算"""
class Test2:
def __init__(self, a, b):
self.a = a
self.b = b
@property
def add(self):
return self.a + self.b
@property
def reduce(self):
return self.a - self.b
print(Test2(3, 1).add) # 結(jié)果:4
print(Test2(5, 2).reduce) # 結(jié)果:3
2. 類對(duì)象中的方法
類對(duì)象中的方法:實(shí)例方法贱勃、類方法和靜態(tài)方法
- 實(shí)例方法:函數(shù)中的第一個(gè)參數(shù)為self的方法
- 靜態(tài)方法:使用@staticmethod裝飾器來將類中的函數(shù)定義為靜態(tài)方法井赌。
類中創(chuàng)建的一些方法,但該方法并不需要引用類或?qū)嵗笕拧lo態(tài)方法通過類直接調(diào)用仇穗,無需創(chuàng)建對(duì)象,也無需傳遞self戚绕。 - 類方法:使用@classmethod裝飾器來裝飾類中的函數(shù)定義為類方法纹坐。
類方法不需要實(shí)例化,也不需要self參數(shù)列肢,函數(shù)中第一個(gè)參數(shù)是自身的cls參數(shù)恰画,可用來調(diào)用類的屬性宾茂、方法和實(shí)例化對(duì)象。
"""實(shí)例方法拴还、靜態(tài)方法@staticmethod跨晴、類方法@classmethod"""
class Student:
description = "學(xué)員統(tǒng)計(jì)信息"
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def function(self, fun_type):
return fun_type
def instance_method(self): # 實(shí)例方法
use_type = self.function("實(shí)例方法")
print("------%s------" % use_type)
print(Student.description)
print(self.name + '_' + str(self.age) + '_' + self.sex)
@staticmethod # 靜態(tài)方法
def static_method():
student_info = Student("xiaoxiao", 20, "female")
use_type = student_info.function("靜態(tài)方法")
print("------%s------" % use_type)
print(Student.description)
print(student_info.name + '_' + str(student_info.age) + '_' + student_info.sex)
@classmethod # 類方法
def class_method(cls):
student_info = cls("xiaoming", 23, "male")
use_type = student_info.function("類方法")
print("------%s------" % use_type)
print(Student.description)
print(student_info.name + '_' + str(student_info.age) + '_' + student_info.sex)
def call_different_method(self):
print("------同一類對(duì)象中調(diào)用實(shí)例方法、靜態(tài)方法片林、類方法------")
self.instance_method()
self.static_method()
self.class_method()
# 實(shí)例方法
Student("xiaohong", 19, "female").instance_method()
# 靜態(tài)方法
Student.static_method()
# 類方法
Student.class_method()
# 同一類對(duì)象中某個(gè)函數(shù)調(diào)用實(shí)例/靜態(tài)/類方法
Student("xiaohong", 19, "female").call_different_method()
三端盆、使用三方已封裝的裝飾器
- 三方模塊decorator
先安裝decorator模塊,再導(dǎo)入from decorator import decorator - 三方模塊wrapt
先安裝wrapt模塊费封,再導(dǎo)入import wrapt
# decorator三方模塊
from decorator import decorator
@decorator
def My_decorator(func, *args, **kwargs):
print("********")
print("添加封裝的功能內(nèi)容")
return func(*args, **kwargs)
@My_decorator
def testScript2():
print("待裝飾的函數(shù)")
testScript2()
# wrapt三方模塊
import wrapt
"""裝飾器不帶參數(shù)"""
@wrapt.decorator
def My_decorator(wrapped, instance, args, kwargs):
# instance參數(shù)即使用不使用也必須保留
print("********")
print("添加封裝的功能內(nèi)容")
return wrapped(*args, **kwargs)
@My_decorator
def testScript1():
print("待裝飾的函數(shù)")
testScript1()
"""裝飾器帶參數(shù)"""
def My_decorator(name):
@wrapt.decorator
def inner(wrapped, instance, args, kwargs):
print("********")
print("添加封裝的功能內(nèi)容焕妙,且裝飾器參數(shù)為%s" % name)
return wrapped(*args, **kwargs)
return inner
@My_decorator(set)
def testScript1():
print("待裝飾的函數(shù)")
testScript1()