Discuss / Python / 麻烦大神解答一下,下面这3个例子理解property是否正确,看了几遍对于property内部如何实现还是不理解

麻烦大神解答一下,下面这3个例子理解property是否正确,看了几遍对于property内部如何实现还是不理解

Topic source
#比较1 - 暴露真正属性值,直接修改属性值
#优点:直接修改属性,很方便;缺点:直接暴露修改属性值容易出现错误
class Student(object):
    def __init__(self, name):       #必选属性name,输入name属性值才可以创建实例
        self.name = name
    __slots__ = ('name', 'score')       #设置类只有2种属性

Student.name        #输出<member 'name' of 'Student' objects>,‘member’说明'name'是一个属性
s = Student('lisa')     #创建实例s
s.score = 90        #只要知道属性的名称就可以通过等式修改任意属性
#比较2 - 保护真正属性名称,使用实例方法修改属性值
#优点:保护属性值不会被随意修改;缺点:使用实例方法比较复杂,没有直接修改属性方便
class Student(object):
    def __init__(self, name):       #必选属性name,输入name属性值才可以创建实例
        self.name = name
    __slots__ = ('name', 'real_score')       #真正的属性名称为real_score
    def get_score(self):        #定义读取属性real_score的方法
         return self.real_score
    def set_score(self, value):     #定义修改属性real_score的方法
        self.real_score = value

Student.get_score       #输出<function __main__.Student.get_score(self)>,说明'get_score'是类的函数
s = Student('lisa')     #创建实例s
s.score = 90        #失败,因为score并不是真正的属性名称
s.get_score     #输出<bound method Student.get_score of <__main__.Student object at 0x地址>>,说明'get_score'是实例的方法
s.set_score(90)        #通过实例方法去修改属性,其实并不知道修改的是哪个属性,自能通过doc说明来理解
s.get_score()       #输出90,通过实例方法去读取属性
s.real_score = 100      #如果知道真实的属性名称为'real_score',仍然可以直接修改属性值
s.real_score        #输出100,如果知道真实的属性名称为'real_score',仍然可以通过属性直接读取
#比较3 - 通过property来保护真正属性名称,并且模拟属性方法来修改属性值
class Student(object):
    def __init__(self, name):       #必选属性name,输入name属性值才可以创建实例
        self.name = name
    __slots__ = ('name', 'real_score')       #真正的属性名称为real_score
    @property       #通过property装饰器(或者property函数)来创建一个模拟属性‘score’,并且定义读取模拟属性’score‘的方法
    def score(self):
         return self.real_score
    @score.setter       #property函数默认会创建(getter, setter, deleter三个子函数),分别对应模拟属性‘score’的读取,修改和删除
    def score(self, value):
        self.real_score = value
    @property
    def grade(self):
        if self.real_score > 90:
            return 'A'
        elif self.real_score > 60:
            return 'B'
        else:
            return 'C'

Student.name        #可见真正的属性’name‘和'real_score'的类型为member
Student.score       #通过@property生成的模拟属性'score'类型为property,并不是member
Student.name.__get__        #输出<method-wrapper '__get__' of member_descriptor object at 0x地址>,属性'name'的读取是通过方法
Student.score.__dir__()     #可以看见@property输出了[ 'getter','setter','deleter']函数
Student.score.getter        #输出<function property.getter>,属性'score'的读取是通过函数

s = Student('lisa')     #创建实例s
s.score = 100       #实际调用的是score.setter, 如果前面定义部分没有@score.setter则score会变为只读属性
s.score       #输出100,实际调用的是score.getter
s.grade     #输出'A'
s.grade = 'B'       #输出AttributeError: can't set attribute,该模拟属性'grade'只读,不可修改

  • 1

Reply