Python @property 基本用法和缺点

本文整理自《Effective Python 编写高质量 Python 代码的 59 个有效方法》第 31 条:用描述符来改写需要复用的 @property 方法

@property 基本用法

@property 修饰器,需要在类中先对某属性同名方法进行修饰器附加,再以 @属性名.setter 的修饰器对该方法进行改写:

class Homework(object):
    def __init__(self):
        self._grade = 0

    @property
    def grade(self):
        return self._grade

    @grade.setter
    def grade(self, value):
        if not (0<= value <= 100):
            raise ValueError('Grade must be between 0 and 100')
        self._grade = value


if __name__ == '__main__':
    ted = Homework()
    ted.grade = 95
    print(f"ted's grade is {ted.grade}")
    ted.grade = 101
    print(f"ted's grade is {ted.grade}")

运行后先是正常打印成绩 95,之后因为成绩 101 超出范围报错:

ted's grade is 95
Traceback (most recent call last):
	... ...
    raise ValueError('Grade must be between 0 and 100')
ValueError: Grade must be between 0 and 100

@property 方法缺点

从上方实例可以看出,@property 对每个属性要配两个修饰器方法来写,很明显不便于复用。

假设我们设计一个考试成绩类,考试成绩由多个科目小成绩组成,每科单独计分:

class Exam(object):
    def __init__(self):
        self._writing_grade = 0
        self._math_grade = 0

    @staticmethod
    def _check_grade(value):
        if not (0 <= value <= 100):
            raise ValueError('Grade must be between 0 and 100')

随着科目不断添加,@property 方法需要不断重复写,相关验证逻辑也要重做:

class Exam(object):
    def __init__(self):
        self._writing_grade = 0
        self._math_grade = 0

    @staticmethod
    def _check_grade(value):
        if not (0 <= value <= 100):
            raise ValueError('Grade must be between 0 and 100')

    @property
    def writing_grade(self):
        return self._writing_grade

    @writing_grade.setter
    def writing_grade(self, value):
        self._check_grade(value)
        self._writing_grade = value

    @property
    def math_grade(self):
        return self._math_grade

    @math_grade.setter
    def math_grade(self, value):
        self._check_grade(value)
        self._math_grade = value


if __name__ == '__main__':
    ted = Exam()
    ted.writing_grade = 95
    print(f"ted's writing grade is {ted.writing_grade}")
    ted.math_grade = 101
    print(f"ted's math grade is {ted.math_grade}")

可以看出,这种写法也不够通用,需要反复编写例行的 @property 代码和 _check_grade 方法。

你可能感兴趣的:(python学习,python资源,python,property,EffectivePython)