Python object-oriented | class attribute

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解释器会先到类的空间里看看有没有这个被装饰的属性,如果有就不能再在自己对象的空间中创建这个属性了

Guess you like

Origin www.cnblogs.com/Summer-skr--blog/p/11801424.html