property
property is a function of decorator, you may be a method of disguise properties , plus the call is made without (). @property method to be decorated, the parameter is not passed because it disguised as a property.
Use decorators: to be decorated in functions, methods, classes plus the top line @ decorator name
Decorators Category:
- Decorative function
- Decorating method: property
- Decoration
Example One: BMI index (bmi is calculated from, but obviously it sounds like a property rather than method, if we make it into a property, easier to understand)
Adult BMI values:
Too light: less than 18.5
Normal: 18.5-23.9
Too heavy: 24-27
Obesity: 28-32
Very fat, higher than 32
Body mass index (BMI) = body weight (kg) ÷ height ^ 2 (m)
EX:70kg÷(1.75×1.75)=22.86
View my BMI
class Person(object): def __init__(self,name,weight,height): self.name = name self.__weight = weight self.__height = height @property def bmi(self): return self.__weight / self.__height **2 p = Person('xiao',65,1.75) print(p.bmi) # 21.224489795918366 print(Person.__dict__) Print . (P the __dict__ ) # object inside, and not as the attribute '' ' performs an output: 21.224489795918366 {' __module__ ':' __main__ ',' the __init__ ': <function the Person .__ init__ AT 0x000002221B1EC048>, ' BMI ': <Property Object AT 0x000002221B1E8C78> , 'the __dict__': <attribute 'the __dict__' of 'the Person' Objects>, '__weakref__': <attribute '__weakref__' of 'the Person' Objects>, 'the __doc__': None} { 'name': 'Xiao', '_Person__weight': 65, '_Person__height': 1.75} '' '
The property is decorated bmi is still a method, there is a Person .__ dict__. .__ dict__ object does not store this property.
Code below, the above effect can be achieved
class the Person (Object): DEF the __init__ (Self, name, weight, height): the self.name = name . Self __weight = weight Self. __height = height # self.bmi Self .__ = weight / height Self .__ ** 2 # Self = cal_BMI .bmi () # the computing logic, which can not be put init. Initialization, do not do the calculation
For example:
class the Person (Object): DEF the __init__ (Self, name, weight, height): the self.name = name . Self __weight = weight Self. __height = height self.bmi = Self. __weight / Self. __height ** 2 P = the Person ( ' Xiao ' , 65,1.75 ) Print (p.bmi) p._Person__weight = 70 # after one week, the weight increase Print (p.bmi) '' ' performs the output: 21.224489795918366 21.224489795918366 '''
The results are the same, weight gain, but the bmi index remained unchanged. Since __init__ after initialization, it will not change the.
In __init__ inside, attribute name and method name can not be repeated
class Person(object): def __init__(self,name,weight,height,bmi): self.name = name self.__weight = weight self.__height = height self.bmi = bmi def bmi(self): return self.__weight / self.__height **2 a = Person('xiao',65,1.75) print(a.bmi()) # TypeError: __init__() missing 1 required positional argument: 'bmi'
Bmi whether it can amend it?
class Person(object): def __init__(self,name,weight,height): self.name = name self.__weight = weight self.__height = height @property def bmi(self): return self.__weight / self.__height **2 p = Person('xiao',65,1.75) p.bmi = 2 # AttributeError: can't set attribute
But its name property can be changed.
class Person: def __init__(self,name): self.name = name p = Person('Tony') print(p.name) # Tony p.name = 'John' p.name = 123
So these two examples above, define the name and direct property What is the difference?
class the Person: DEF __init__ (Self, name): . Self __name__ = name # private property the @Property DEF name (Self): return Self. __name__ DEF set_name (Self, new_name): IF of the type (new_name) IS str: Self. __name__ = new_name the else : # pass judgment if the type of property you can protect, must be a string Print ( ' name the data type you provide illegal ' ) the p- = the Person ( ' Tony ' ) Print (p.name) p.set_name ( ' John ' ) Print (p.name) p.set_name ( 123 ) '' ' execute output: Tony John name data type you supplied is not lawful ' ''
@property can python defined function "as" property access, sometimes setter / deleter also needed.
-
Only @property for read-only.
-
While @property and @ x.setter means read and write.
-
While @property and @ x.setter and @ x.deleter means read and write can be deleted.
The new class has three access methods, three methods are defined as the same property: acquiring, modify, delete
class Foo: the @Property DEF AAA (Self): Print ( ' GET when I run ah ' ) @ AAA.setter DEF AAA (Self, value): Print ( ' the SET when I run ah ' ) @ AAA.deleter DEF AAA (Self): Print ( ' the Delete when I run ah ' ) # can only be defined AAA.setter, AAA.deleter AAA attributes defined in the property f1 = Foo () f1.AAA f1.AAA = ' aaa ' del f1 .aaa '' ' performs the output: I ah get run when I run ah set when delete when I run ah '' '
or:
class Foo: DEF get_AAA (Self): Print ( ' GET time to run my ah ' ) DEF set_AAA (Self, value): Print ( ' the SET time to run my ah ' ) DEF delete_AAA (Self): Print ( ' the Delete the when I run ah ' )
AAA = property (get_AAA, set_AAA, delete_AAA) # built property three parameters with get, set, delete correspondence f1 = Foo () f1.AAA f1.AAA = ' aaa ' del f1.AAA '' ' execute output: GET when I run ah I run ah set when the SET time to run my ah delete when I run ah '' '
Commercial examples
class Goods(object): def __init__(self): self.original_price = 100 # 原价 self.discount = 0.8 # 折扣 @property def price(self): # 计算折后价格 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self, value): del self.original_price obj = Goods() print(obj.price) # 获取商品价格 80.0 obj.price = 200 # 修改商品原价 print(obj.price) # 获取商品价格 160.0 # del obj.price # 删除商品原价 TypeError: price() missing 1 required positional argument: 'value'
class Person: def __init__(self,name): self.__name = name # 私有的属性 @property def name(self): return self.__name @name.setter def name(self,new_name): print('---',new_name) p = Person('Tony') p.name = 'John' # 修改name属性 ''' 执行输出: --- John '''
上面的代码,3个name必须是相同的。三位一体。@name.settet有且并只有一个参数
class Person: def __init__(self,name): self.__name = name # 私有的属性 @property def name(self): return self.__name @name.setter def name(self,new_name): print('---',new_name) p = Person('Tony') print(p.name) p.name = 'John' # 修改name属性 print(p.name) ''' 执行输出: Tony --- John Tony '''
从结果上来看,并没有改变Tony的值那么如何改变呢?看下面的代码
class Person: def __init__(self,name): self.__name = name # 私有的属性 @property def name(self): return self.__name @name.setter def name(self,new_name): self.__name = new_name # 更改__name属性 p = Person('Tony') print(p.name) p.name = 'John' # 修改name属性 print(p.name) ''' 执行输出: Tony John '''
但是这样,不能保证修改的数据类型是固定的
class Person: def __init__(self,name): self.__name = name # 私有的属性 @property def name(self): return self.__name @name.setter def name(self,new_name): if type(new_name) is str: self.__name = new_name else: print('您提供的姓名数据类型不合法') p = Person('Tony') print(p.name) p.name = 'John' # 修改name属性 print(p.name) p.name = 123 # 不合法 print(p.name) ''' 执行输出: Tony John 您提供的姓名数据类型不合法 John '''
非法类型,不允许修改,这样就可以保护属性的类型
方法伪装成的属性删除操作
class Person: def __init__(self,name): self.__name = name # 私有的属性 @property def name(self): return self.__name p = Person('alex') print(p.name) del p.name # AttributeError: can't delete attribute
# 为什么不能删除?因为name被@property伪装了,此时name是只读的。
那么如何删除呢?看下面的代码
class Person: def __init__(self,name): self.__name = name # 私有的属性 @property def name(self): return self.__name @name.deleter def name(self): del self.__name p = Person('Tony') print(p.name) del p.name print(p.__dict__) # 查看属性 ''' 执行输出: Tony {} '''
p对象返回的是空字典,说明删除成功了!
3个装饰器的重要程度
- @property****
- @name.setter ***
- @name.deleter *
再讲一个列子:商品的 折扣 我想看折后价
class Goods: def __init__(self,name,origin_price,discount): self.name = name self.__price = origin_price # 原价 self.__discount = discount # 折扣价 @property def price(self): return self.__price * self.__discount apple = Goods('apple',5,0.8) print(apple.price) # 4.0
修改苹果的原价
class Goods: def __init__(self,name,origin_price,discount): self.name = name self.__price = origin_price # 原价 self.__discount = discount # 折扣价 @property def price(self): # 价格 return self.__price * self.__discount @price.setter def price(self,new_price): if type(new_price) is int or type(new_price) is float: self.__price = new_price apple = Goods('apple',5,0.8) print(apple.price) # 4.0
apple.price = 8 # # 修改苹果的原价 print(apple.price) # 6.4
被property装饰的方法,不能修改,只能查看
圆形类,有半径,面积,周长。要求:将方法伪装成属性,方法中一般涉及的都是一些计算过程
from math import pi class Circle: # 圆形 def __init__(self, r): self.r = r @property def area(self): # 面积 return pi * self.r ** 2 @property def perimeter(self): # 周长 return pi * self.r * 2 c = Circle(10) print(c.area) print(c.perimeter) c.r =15 # 修改半径 print(c.area) print(c.perimeter) ''' 执行输出: 314.1592653589793 62.83185307179586 706.8583470577034 94.24777960769379 '''
总结:
-
@property --> func 将方法伪装成属性,只观看的事儿
-
@func.setter --> func 对伪装的属性进行赋值的时候调用, 一般情况下用来做修改
-
@func.deleter --> func 在执行del 对象.func的时候调用,一般情况下用来做删除.基本不用
property的作用:
-
将一些需要随着一部分属性的变化而变化的值的计算过程 从方法 伪装成属性
-
将私有的属性保护起来,让修改的部分增加一些约束,来提高程序的稳定性和数据的安全性
在一个类加载的过程中,会先加载这个类的名字,包括被property装饰的。
在实例化对象的时候,python解释器会先到类的空间里看看有没有这个被装饰的属性,如果有就不能再在自己对象的空间中创建这个属性了