python面向对象三个常见装饰器
前言
本篇文章我要讲述的是python面向对象的三个常见装饰器,它们分别是封装能够访问私有属性之方法的**@property**,封装类方法的**@classmethod**,以及封装静态方法的**@staticmethod**。这三者之间的区别就在于使用的变量是来自对象的属性还是类本身的属性,亦或者二者皆不是。
下面我将用一个案例来描述刚刚提到的不同属性的区别一个三种装饰器的应用。
不同的属性
属性按外部是否可调用分为私有属性(外部不可访问)、非私有属性(外部可访问);按是否为所有对象共有分为公共属性(也叫类属性)和实例属性。
举个例子,现在老板给了一个工作任务,一个人的话大约需要100小时才能完成,假设该任务可以由同一部门的人接力完成,每个人都将按照自己的工作时长加上底薪来要计算薪资。由此,我们可以写一个打工人的类:
class Worker:
work = 100
def __init__(self,name):
self.name = name
self.working_hours = 0
self.__money = 2000
def worked_time(self,time):
self.working_hours += time
Worker.work -= time
print(f"员工{self.name}已经工作{self.working_hours}小时")
每个打工人(对象)都有属于自己的名字、工作时长、以及薪资,但是这三个属性值每个人的都不同,这样的属性叫做实例属性。而所有打工人都在接力做同一项工作,不论是谁工作一小时,总的工作时长都会减少一小时,那么这个剩余工作时长就是所有打工人共享的变量,这个变量就叫做公共属性。
daniu = Worker("大牛")
daniu.worked_time(10)
ergou = Worker("二狗")
ergou.worked_time(10)
print(f"还剩{Worker.work}小时就可以完成") # 访问公共属性
每个人的工资可能都不相同,但是我又不想人其他人知道打工人具体拿了多少钱,我们就可以将工资设置为外部不可访问的属性,这样的属性就叫做私有属性,其写法为两个下划线加变量名。同理还有私有方法也是一样的两个下划线加方法名。而外部可以访问并修改的属性就是非私有属性。
引申:其实我们上面定义的私有化方法和属性是伪私有化方法/属性,可以通过_类名__属性名或方法名的方式访问:
# print(daniu.__money) # 直接访问私有属性,会报错
print(daniu._Worker__money) #可访问
装饰器@property,方法属性化
装饰器@property封装的方法实际上就是一个返回私有属性的方法,其作用就是将该方法属性化。还是接着上面的例子接着说,每个打工人的工资都是底薪加上完成的工时所对应的酬劳,再减去每月固定的保险支出。
class Worker:
"""..."""
def set_money(self):
self.__money += self.working_hours * 10
print(f"员工{self.name}应发工资{self.__money}元")
@property
def gongzi(self):
self.__money -= 500
print("扣除保险费用500元")
return self.__money
注意:@property装饰器的作用是将方法属性化,所以该方法的最后一定是要返回一个值的,而且在调用时不用再加括号。
daniu.set_money()
print(daniu.gongzi)
装饰器@classmethod,定义类方法
类属性 在python中用于创建对象的类也是一个对象,叫类对象(如Worker)。通过类(类对象)创建对象的动作叫做类(类对象)的实例化,通过类(类对象)创建的对象的属性叫实例属性(如daniu.name),而类属性是给类队形中定义的属性(如Worker.work),通常用来记录与这个类相关的特征,类属性不会用于记录具体对象的特征。实际上类属性就是公共属性的另一种理解或和描述
**类方法 ** 通过类创建的对象调用的方法叫做实例方法,而针对类对象(类)定义的方法就叫类方法,在类方法内部可以直接访问类属性或者调用其他的类方法,其关键字是cls,原理同self。定义类方法是在方法名前加装饰器@classmethod
class Worker:
"""..."""
@classmethod
def add_work(cls,n):
cls.work += n
print(f"万恶的老板又增加了{n}小时的工作量,要把工作做完还需要{cls.work}小时")
在外部调用add_work()这个类方法的时,格式跟实例方法没多大区别,实例方法的调用时实例名加方法名,类方法的调用是类名加方法名或者实例名加方法名都可以:
Worker.add_work(20) # 用类名加方法名调用,共享属性Worker.work增加了20
daniu.add_work(20) # 用实例名加方法名调用,共享属性Worker.work第二次增加20
ergou.add_work(20) # 用另外的实例名加方法名调用,共享属性Worker.work第三次增加20
引申:除了使用装饰器以外,也可以直接在实例方法中直接调用共享属性,只不过此时共享属性得写全名(类名加属性名)。反正有装饰器不用,就是玩儿。
当然了,如果你想写一个类,里面有一整套方法,但你又不想创建实例就直接调用,就可以封装一个完全由类属性(共享属性)和类方法组成的类。
装饰器@staticmethod,定义静态方法
如果说一个类里面不加任何装饰器写的实例方法是涉及实例属性,加装饰器classmethod写的类方法是涉及类属性(共享属性),那么与前二者相对应的就是静态方法。静态方法不涉及任何实例属性或方法也不涉及任何类属性或类方法,定义静态方法就是在方法名前面加上装饰器@staticmethod
class Worker:
"""..."""
@staticmethod
def fun():
print("打工人,打工魂,打工都是人上人")