第二十二天python3 classmethod、staticmethod、property装饰器学习笔记
classmethod
1、在类定义中,使用@classmethod装饰器修饰的方法;
2、必须至少有一个参数,且第一个参数留给了cls,cls指代调用者即类对象自身;
3、cls这个标识符可以是任意合法名称,但是为了易读,不要修改;
4、通过cls可以直接操作类的属性;但是无法通过cls操作类的实例,因为有类的时候未必有实例,就算有实例,一个类可以有多个实例,并不能确定操作哪个实例;
class Person: def __init__(self): print(id(self),"这是self的ID") @classmethod def people(cls): print(id(cls()), "这是cls()的ID") Person.people() # 这属于类方法调用,如果classmethod发现是类方法,则将类传递进去作为参数,也就是people(cls)。 print("######") Person().people() # 这属于实例方法调用,如果classmethod发现是实例方法,则将实例的类传递进去。
"""执行结果:
1238665306800 这是self的ID
1238665306800 这是cls()的ID
######
1238665306800 这是self的ID
1238665306800 这是self的ID
1238665306800 这是cls()的ID
"""
根据上述代码可知:cls的本质就是一个类,也就是上面代码的Person类本身。cls()和self都是类的实例也就是类对象,所以他们ID相同。classmethod所装饰的方法被称为类方法,因此第一个传进来的参数就不是self了,而是class类。
那么classmethod能做什么呢?1、可以修改类属性的值。2、产生类的实例
1、修改类属性的值
class Person: ID = 0 def __init__(self,name): self.name = name @classmethod def people(cls,age): cls.ID += age return cls.ID P = Person('zhang') print(P.people(18)) print(Person.__dict__) """执行结果: 18 {'__module__': '__main__', 'ID': 18, '__init__': <function Person.__init__ at 0x0000021CE8068C10>, 'people': <classmethod object at 0x0000021CE800A5B0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None} """
从上述代码中可知:Person类的默认属性ID的值为0,可以通过传值的方式将ID的默认值修改。同时也能在Person类的属性列表中看到。
2、产生类的实例
"""1675847343.624 0.001 192.168.80.89 - 204 0 POST http://gitlab.test.com/api/v4/jobs/request - NONE/127.0.0.1:8099""" class Log: def __init__(self,time,request_time,remote_addr,x_forword_f,status,body_bytes,method,url,remote_user,upstream_addr): self.time = time self.request_time = request_time self.remote_addr = remote_addr self.x_forword_f = x_forword_f self.status = status self.body_bytes = body_bytes self.method = method self.url = url self.remote_user = remote_user self.upstream_addr = upstream_addr @classmethod def analysis(cls,data): time,request_time,remote_addr,x_forword_f,status,body_bytes,method,url,remote_user,upstream_addr = data.split(" ") return cls(time,request_time,remote_addr,x_forword_f,status,body_bytes,method,url,remote_user,upstream_addr) L = "1675847343.624 0.001 192.168.80.89 - 204 0 POST http://gitlab.test.com/api/v4/jobs/request - NONE/127.0.0.1:8099" A = Log.analysis(L) print(A.time,A.method,A.url)
上述代码中,通过切割日志,将值传递给cls(),生成类的实例,然后就可以按需获取所需要的字段。
staticmethod
1、在类定义中,使用@staticmethod装饰器修饰的方法;
2、调用时,不会隐式传入参数,静态方法只是表明这个方法属于这个名词空间,和函数归在一起,方便组织管理;
import datetime class Person: def __init__(self,name,age): self.name = name self.age = age @staticmethod def dtime(): nowtime = datetime.datetime.now() return nowtime print(Person.dtime()) print(Person('zhang',18).dtime()) print(Person.__dict__)
静态方法比较简单,功能也相对单一,可以作为类的额外功能,在不用传入self或者cls的情况下,可以读取文件或者记录日期之类的功能。
property
1、一般好的设计是:把实例的属性保护起来,不让外部直接访问,外部使用getter(隐式传入)读取属性和setter方法设置属性;
2、用property装饰器生成的属性称为只读属性;property可以单独存在;
3、property装饰器必须在前,setter,deleter装饰器在后;
4、property装饰器能通过简单的方式,把对方法的操作变成对属性的访问,也就是将函数的返回值作为类的属性,调用这个被装饰的函数不需要去加括号运行,而是直接像调用类属性一样获取值。
5、加了setter装饰器之后就是可读可写属性;且接收2个参数,第一个是self,第二个是将要赋值的值;但是setter不能单独存在;
6、删除函数基本不用;
class Person: def __init__(self,name,age): self.name = name self.age = age @property def per_age(self): # 只读属性 return self.age @per_age.setter # 给属性增加修改属性 def per_age(self,age): self.age = age @per_age.deleter def per_age(self): # del的功能取决于你自己在这里设置的操作 print('del age') self.age = None P = Person('zhang',18) # 在P.per_age被注释的情况下,打印的结果是18。 # P.per_age = 30 # 在该句取消注释的情况下,在类外部重新定义了per_age属性的返回值。 print(P.per_age) del P.per_age # 返回del功能内所做的操作的返回值。 print(P.per_age)
实现温度间的转换
#!/usr/bin/env python # -*- encoding: utf-8 -*- """ ℃ = 5 x (℉ - 32) / 9 摄氏度 ℉ = 9 x ℃ / 5 + 32 华氏度 K = ℃ + 273.15 开氏温度 """ class Temperature: def __init__(self,num,unit="c"): self._c = None self._f = None self._k = None if unit == "f": self._f = num self._c = self.f2c(num) self._k = self.f2k(num) elif unit == "k": self._k = num self._c = self.k2c(num) self._f = self.k2f(num) else: self._c = num self._f = self.c2f(num) self._k = self.c2k(num) @property def c(self): return self._c @property def f(self): if self._f is None: self._f = self.c2f(self._c) return self._f @property def k(self): if self._k is None: self._k = self.c2k(self._c) return self._k @classmethod def c2f(cls,c): return 9 * c/5 + 32 @classmethod def c2k(cls,c): return c + 273.15 @classmethod def f2c(cls,f): return 5 * (f - 32) / 9 @classmethod def f2k(cls,f): return cls.f2c(f) + 273.15 @classmethod def k2c(cls,k): return k - 273.15 @classmethod def k2f(cls,k): return 9 * cls.k2c(k) / 5 + 32 # 示例:开氏温度转华氏温度 t = Temperature(100,"k") print(t.f)