|
本文分为两部分,第一部分是介绍python中常见的装饰器。另一部分是自定义装饰器,包括了一些非常好用的自定义装饰器。一文搞懂python中常用的装饰器常见的几个装饰器介绍及示例@classmethod装饰器基本用法@property、@setter装饰器基本用法@staticmethod装饰器基本用法@abstractmethod装饰器基本用法自定义装饰器类装饰器非常好用的自定义装饰器常见的几个装饰器介绍及示例@classmethod装饰器基本用法定义及语法@classmethod装饰器用于定义类方法。类方法与普通方法不同,它在类层级上操作,而不是在实例层级上。通过类方法,我们可以直接通过类名调用方法,而无需创建类的实例。并且第一个参数通常被命名为cls,代表类本身,而不是常见的self。类方法可以访问类的属性和其他类方法(不包括实例方法),但不能直接访问实例的属性。以下是使用@classmethod装饰器定义类方法的语法:classMyClassclassmethoddefmy_method(cls,arg1,arg2,...):#方法体1234三种常用使用场景及示例示例1:访问类的属性搭配使用,注意不是实例的属性self.xxx。示例中统计创建了多少个对象。classMyClass:count=0#类的属性而不是实例属性def__init__(self):MyClass.count+=1@classmethoddefget_count(cls):returncls.countobj1=MyClass()obj2=MyClass()obj3=MyClass()print(MyClass.get_count())#输出:31234567891011121314示例2:从字符串中创建对象,类方法可以提供一种替代构造方法的方式。classPerson:def__init__(self,name,age):self.name=nameself.age=agedefdisplay(self):print(f"Name:{self.name},Age:{self.age}")@classmethoddeffrom_string(cls,string):name,age=string.split(",")returncls(name,int(age))person_str="John,25"person=Person.from_string(person_str)person.display()#输出:Name:John,Age:2512345678910111213141516在这个例子中,我们通过from_string()方法从一个字符串中创建了一个Person对象。该方法接收一个字符串,将字符串按照分隔符创建,并返回一个新的Person对象。示例3:根据不同的类型参数返回不同的子类对象。classShape:def__init__(self,color):self.color=colordefdisplay_color(self):print(f"Color:{self.color}")@classmethoddefcreate_shape(cls,color,type):iftype=="circle":returnCircle(color)eliftype=="rectangle":returnRectangle(color)classCircle(Shape):defdisplay_shape(self):print("Type:Circle")classRectangle(Shape):defdisplay_shape(self):print("Type:Rectangle")circle=Shape.create_shape("red","circle")circle.display_color()#输出:Color:redcircle.display_shape()#输出:Type:Circlerectangle=Shape.create_shape("blue","rectangle")rectangle.display_color()#输出:Color:bluerectangle.display_shape()#输出:Type:Rectangle1234567891011121314151617181920212223242526272829在这个示例中,我们通过工厂模式创建了Shape的子类对象。create_shape()方法根据不同的类型参数返回不同的子类对象,达到生成不同形状的对象的目的。注意事项:类方法中不能调用实例方法(第一个参数是self的方法)。但可以调用其他类方法或者静态方法(@staticmethod),示例如下。classMyClassclassmethoddefclass_method(cls):print("Thisisaclassmethod")cls.other_method()cls.other_method2()@staticmethoddefother_method():print("Thisisanothermethod")definstance_method(self):print("Thisisaninstancemethod")@classmethoddefother_method2(cls):print("Thisisanothermethod")obj=cls()obj.instance_method()#调用类方法MyClass.class_method()12345678910111213141516171819202122@property、@setter装饰器基本用法定义@property装饰器是Python中一个特殊的装饰器,用于定义类的属性。它提供了一种简洁的方式来定义属性的访问方法,并且可以在需要时进行计算或验证。应用于类的实例方法,将其转换为类的属性。通过使用@property装饰器,可以将一个方法定义为只读属性,也可以定义一个可读写的属性,并且可以实现属性删除。@setter装饰器用于定义一个属性的setter方法,用于修改属性的值。使用@setter时,我们需要在@property装饰的属性方法之后,紧跟一个setter方法,并使用@属性名.setter来装饰该方法@setter通常用于以下场景:当一个属性的值需要计算得到,而不是直接存储在类的属性中时,我们可以使用@setter来提供一个修改属性值的接口。当某个属性的值需要经过一些处理后再进行存储时,我们可以使用@setter来自动执行处理操作。基本用法示例1:可读写属性、属性删除classPerson:def__init__(self,name):self._name=name#私有属性@propertydefname(self):#读取私有属性returnself._name@name.setter#可写属性defname(self,value):self._name=value@name.deleterdefname(self):#删除属性delself._nameperson=Person("Alice")print(person.name)#输出:Alicedelperson.nameprint(person.name)#抛出AttributeError异常,属性已被删除1234567891011121314151617181920在上面的例子中,name属性定义了获取、设置和删除方法。通过使用@property.deleter装饰器,定义了name属性的删除方法。在删除name属性时,可以使用del语句。示例2:属性计算,@property装饰器可以用于对属性的计算,使得通过访问属性时能够返回计算后的结果。classRectangle:def__init__(self,width,height):self._width=widthself._height=height@propertydefwidth(self):returnself._width@width.setterdefwidth(self,value):ifvalue>=0:self._width=valueelse:raiseValueError("Widthmustbeanon-negativenumber.")@propertydefheight(self):returnself._height@height.setterdefheight(self,value):ifvalue>=0:self._height=valueelse:raiseValueError("Heightmustbeanon-negativenumber.")@propertydefarea(self):returnself._width*self._height@propertydefperimeter(self):return2*(self._width+self._height)rectangle=Rectangle(4,5)print(rectangle.width)#Output:4print(rectangle.height)#Output:5print(rectangle.area)#Output:20print(rectangle.perimeter)#Output:18rectangle.width=6rectangle.height=8print(rectangle.width)#Output:6print(rectangle.height)#Output:8print(rectangle.area)#Output:48print(rectangle.perimeter)#Output:28123456789101112131415161718192021222324252627282930313233343536373839404142434445464748在上面的代码中,我们定义了一个名为Rectangle的类,它具有width、height、area和perimeter四个属性。面积和周长是通过width和height属性的计算得到的,通过使用@property装饰器,我们将这两个方法定义为属性。注意:静态方法和类方法:@property装饰器只能应用于实例方法,而不能应用于静态方法或类方法。它是用于访问实例属性的装饰器。私有属性:私有属性是名称前面添加一个下划线,例如self._property。这样可以向其他开发人员传达属性的可见性意图,虽然在Python中并没有真正的私有属性,私有属性也可以被访问。调用setter:在setter方法内部,我们使用self.属性名对属性进行赋值。在调用setter方法时,我们只需要给属性赋值,不需要加圆括号。@staticmethod装饰器基本用法定义@staticmethod装饰器是Python中用于定义静态方法的装饰器。静态方法是与类相关联但不依赖于实例的方法。它们可以直接通过类名调用,而无需创建类的实例。静态方法具有以下特点:不访问实例状态:静态方法不需要访问实例的状态或属性。它们通常用于执行与类相关的功能,但与特定实例无关。通过类名调用:静态方法可以直接通过类名调用,而无需创建类的实例。这使得静态方法在不依赖于实例的情况下提供了一种方便的功能。不需要self参数:静态方法的定义不需要self参数。由于静态方法不操作实例的状态,因此不需要将实例作为参数传递。不能访问实例变量:静态方法无法访问实例变量,因为它们与实例无关。它们只能访问类级别的属性和其他静态方法。可以访问类级别的属性和方法:静态方法可以访问类级别的属性和其他静态方法。它们可以与类的其他成员进行交互,但无法直接访问实例级别的成员。基本用法示例1:静态方法通常被用于处理和类相关的计算逻辑,而与类实例的状态无关。例如,我们可以在一个日期类中定义一个静态方法,用于判断某一年是否为闰年。因为判断闰年与具体的日期实例无关,所以这个方法可以被定义为静态方法。classDate:def__init__(self,year,month,day):self.year=yearself.month=monthself.day=day@staticmethoddefis_leap_year(year):ifyear%4==0andyear%100!=0oryear%400==0:returnTrueelse:returnFalsedefdisplay_date(self):print(f"Date:{self.year}-{self.month}-{self.day}")#创建日期实例my_date=Date(2022,10,1)#调用静态方法判断是否为闰年ifDate.is_leap_year(my_date.year):print(f"{my_date.year}isaleapyear.")else:print(f"{my_date.year}isnotaleapyear.")123456789101112131415161718192021222324静态方法不需要访问实例的状态或属性,因此不需要传递self参数。在静态方法内部,无法访问类的实例变量,因为它们与实例无关。可以直接使用类名调用静态方法,如Date.is_leap_year(my_date.year),而无需创建类的实例。示例2:类中的静态方法可以被类方法和实例方法访问classMyClassstaticmethoddefstatic_method():print("Thisisastaticmethod.")@classmethoddefclass_method(cls):cls.static_method()print("Thisisaclassmethod.")definstance_method(self):self.static_method()print("Thisisaninstancemethod.")#通过类名调用静态方法MyClass.static_method()#输出:Thisisastaticmethod.#通过类方法调用静态方法MyClass.class_method()#输出:#Thisisastaticmethod.#Thisisaclassmethod.#创建类的实例obj=MyClass()#通过实例调用静态方法obj.static_method()#输出:Thisisastaticmethod.#通过实例方法调用静态方法obj.instance_method()#输出:#Thisisastaticmethod.#Thisisaninstancemethod.1234567891011121314151617181920212223242526272829303132333435@abstractmethod装饰器基本用法@abstractmethod是一个装饰器,用于声明抽象方法。抽象方法是在基类中定义但没有具体实现的方法,它需要在派生类中进行具体的实现。注意事项:抽象方法的主要目的是定义一个接口,规定了派生类必须提供的方法。它在面向对象设计中非常有用,因为它可以确保派生类遵循特定的接口约定。需要注意的是,抽象方法只能在抽象基类中定义,而不能直接实例化抽象基类。因此,抽象基类本身无法被实例化,只能被用作其他类的基类。抽象基类必须继承自ABC基类,并使用@abstractmethod装饰器标记抽象方法。派生类必须实现基类中的抽象方法,否则会引发TypeError。基本用法示例:使用抽象类进行多态fromabcimportABC,abstractmethod#第一步:导入abc#第二步:定义抽象基类classAnimal(metaclass=abc.ABCMeta):#同一类事物:动物@abc.abstractmethoddeftalk(self):pass#第三步:创建派生类并实现抽象方法classCat(Animal):#动物的形态之一:猫deftalk(self):print('Thisisacat')classDog(Animal):#动物的形态之二:狗deftalk(self):print('Thisisadog')c=Cat()d=Dog()deffunc(obj)bj.talk()#同一函数名,根据对象不同实现不同方法func(c)#'Thisisacat'func(d)#'Thisisadog'1234567891011121314151617181920212223242526在上面的例子中,Animal类定义了一个抽象方法talk(),子类Cat和Dog分别实现了这个抽象方法。可以通过抽象类类型的变量来分别引用Cat和Dog类的对象,并调用它们的talk()方法。自定义装饰器#"""装饰器:格式规范"""#第一步:写装饰器函数(使用python内置装饰器时可省略)defdecorator_name(f):#f为被修饰的函数@wraps(f)#@wraps()接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。defdecorated(*args,**kwargs):#对函数f的装饰,即添加新功能ifnotcan_run:return"Functionwillnotrun"returnf(*args,**kwargs)returndecorated#第二步:@装饰器在被装饰的函数func上方,得到被装饰后的func()@decorator_name#@是一种简写,代表了func=decorator_name(func)deffunc():return("Functionisrunning")#此时的func()已经是被装饰后的func()can_run=Trueprint(func())#Output:Functionisrunningcan_run=Falseprint(func())#Output:Functionwillnotrun1234567891011121314151617181920212223242526272829类装饰器非常好用的自定义装饰器请参考此处
|
|