面向对象【林老师版】:特性(property)(十六)

一、什么是特性property

property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)

成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
体质指数(BMI)=体重(kg)÷身高^2(m)
EX:70kg÷(1.75×1.75)=22.86

1、实现代码

class People:
    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)

p1=People('luoahong',55,1.55)
p2=People('typ',65,1.65)
p3=People('tyx',15,1.03)
print(p1.bmi)
print(p2.bmi)
print(p3.bmi)

2、输出结果

class People:
    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)

p1=People('luoahong',55,1.55)
p2=People('typ',65,1.65)
p3=People('tyx',15,1.03)
print(p1.bmi)
print(p2.bmi)
print(p3.bmi)

例二:圆的周长和面积

1、实现代码

import math
class Circle:
    def __init__(self,radius): #圆的半径radius
        self.radius=radius

    @property
    def area(self):
        return math.pi * self.radius**2 #计算面积

    @property
    def perimeter(self):
        return 2*math.pi*self.radius #计算周长

c=Circle(10)
print(c.radius)
print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(c.perimeter) #同上

 2、输出结果

314.1592653589793
62.83185307179586

 注意:此时的特性area和perimeter不能被赋值

c.area=3 #为特性area赋值
'''
抛出异常:
AttributeError: can't set attribute
'''

二、为什么要用property

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

除此之外,看下

ps:面向对象的封装有三种方式:
【public】
这种其实就是不封装,是对外公开的
【protected】
这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
【private】
这种封装对谁都不公开

  python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现

 1、实现代码

class People:
    def __init__(self,name):
        self.__name=name

    @property
    def name(self):
        # print('getter')
        return self.__name

    @name.setter
    def name(self,val):
        # print('setter',val)
        if not isinstance(val,str):
            print('名字必须是字符串类型')
            return
        self.__name=val

    @name.deleter
    def name(self):
        print('deleter')

        print('不允许删除')

p=People('egon')

# print(p.get_name())

print(p.name)

p.name
p.name='EGON'
p.name=123
print(p.name)

del p.name

2、输出结果:

egon
名字必须是字符串类型
EGON
deleter
不允许删除

3、完整注解

class Foo:
    def __init__(self,val):
        self.__NAME=val #将所有的数据属性都隐藏起来

    @property
    def name(self):
        return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在设定值之前进行类型检查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'
posted @ 2018-11-12 10:45  活的潇洒80  阅读(172)  评论(0编辑  收藏  举报