9.21 ����的属性方法¶

问题¶

你在类中需���的定义一些执行相�逻辑的属性方法,比如进行类型检查,怎样去简化这些��代�呢?

解决方案¶

考虑下一个简�的类,它的属性由属性方法包装:

class Person:
    def __init__(self, name ,age):
        self.name = name
        self.age = age

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise TypeError('name must be a string')
        self._name = value

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
        if not isinstance(value, int):
            raise TypeError('age must be an int')
        self._age = value

�以看到,为了实现属性值的类型检查我们写了很多的��代�。 ��你以�看到类似这样的代�,你都应该想办法去简化它。 一个�行的方法是创建一个函数用�定义属性并返回它。例如:

def typed_property(name, expected_type):
    storage_name = '_' + name

    @property
    def prop(self):
        return getattr(self, storage_name)

    @prop.setter
    def prop(self, value):
        if not isinstance(value, expected_type):
            raise TypeError('{} must be a {}'.format(name, expected_type))
        setattr(self, storage_name, value)

    return prop

# Example use
class Person:
    name = typed_property('name', str)
    age = typed_property('age', int)

    def __init__(self, name, age):
        self.name = name
        self.age = age

讨论¶

本节我们演示内部函数或者闭包的一个��特性,它们很�一个�。例�中的函数 typed_property() 看上去有点难�解,其实它所�的仅仅就是为你生�属性并返回这个属性对象。 因此,当在一个类中使用它的时候,效果跟将它里�的代�放到类定义中去是一样的。 尽管属性的 getter 和 setter 方法访问了本地��如 name , expected_type 以� storate_name ,这个很正常,这些��的值会�存在闭包当中。

我们还�以使用 functools.partial() ���改�下这个例�,很有趣。例如,你�以�下�这样:

from functools import partial

String = partial(typed_property, expected_type=str)
Integer = partial(typed_property, expected_type=int)

# Example:
class Person:
    name = String('name')
    age = Integer('age')

    def __init__(self, name, age):
        self.name = name
        self.age = age

其实你�以�现,这里的代�跟8.13�节中的类型系统�述器代�有些相似。