@property,可以用来实现类内方法像变量一样被读取。适合一些格式化输出方法,好处是既访问了类内变量,又保护了类内变量不被外部操作。举例如下:
class A:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
@property
def profile(self):
return "name: "+ self.name + "\nage: " + str(self.age)
if __name__ == "__main__":
a = A("Lily", 18)
print(a.profile)
"""
output:
name: Lily
age: 18
"""
如果没有使用@property,那么要用a.profile()调用。
@xx.setter与@property对应。它需要先定义@property方法,假设方法名为a,则紧跟@a.setter。它的应用场景是对property方法涉及的类内变量进行赋值,进而改变property的返回结果。这种调用方法可以提醒人:更改类内变量的值是为了property方法。调用方式为xx=v。v对应的是setter中传的变量值。
#coding=utf8
class B:
def __init__(self, p):
self.price = p
@property
def actual_price(self):
return "真实价格:" + str(self.price)
@actual_price.setter
def actual_price(self, d):
self.price = self.price * d
if __name__ == "__main__":
b = B(100)
print(b.actual_price)
b.actual_price = 0.3
print(b.actual_price)
'''
output:
真实价格:100
真实价格:30.0
'''
如果在对类变量赋值时需要一些判断,那么,需要用到__set__( )。例子如下:
class age_filter:
def __init__(self, key_name, threshold, default_value):
self.key_name = key_name
self.threshold = threshold
self.default_value = default_value
def __set__(self, obj, value):
if value > self.threshold:
print("correct set !")
obj.__dict__[self.key_name] = value # 特别注意!不能用setattr(obj, self.key_name, value)
else:
print("wrong set !")
obj.__dict__[self.key_name] = self.default_value # 特别注意!不能用setattr(obj, self.key_name, self.default_value)
class adult:
age = age_filter("age", 18, -1)
def __init__(self, n):
self.age = n
if __name__ == "__main__":
a = adult(19)
print(a.age) # 19
b = adult(5)
print(b.age) # -1
这里例子实现了一个adult类,对age进行赋值时会调用age_filter类里的__set__。__set__里的逻辑是,如果value大于self.threshold,那么用value对adult类实例中的self.key_name赋值,否则,用self.default_value对adult类实例中的self.key_name赋值。
age_filter类里一定要有的变量就是self.key_name,用来记录原实例里被赋值的变量名。否则将无法得知原实例中是对什么变量赋值而触发的这个__set__。__set__只能拿到原实例,也就是它的第二个参数obj。在__set__里,如果想对原实例obj进行赋值,那么一定不能用setattr(obj, self.key_name, value),因为这样会导致无限循环调用__set__。要用obj.__dict__[self.key_name]=value来避开触发__set__。
这个age一定要设置成类变量,也就是在__init__之前先让age=age_filter。这样可以让self.age有一个类型:age_filter。后面不管是__init__还是其他方法,再对age进行赋值时,都会因为修改了age_filter而触发age_filter里的__set__。否则,无法让age以age_filter的身份被修改。注意,这个类变量名age要和传入age_filter的key_name一致,否则__set__里的修改不生效。