1. #!/usr/bin/env python
    2. # -*- coding: utf-8 -*-
    3. # 你在类中需要重复的定义一些执行相同逻辑的属性方法,比如进行类型检查,怎样去简化这些重复代码呢?
    4. class Person:
    5. def __init__(self, name, age):
    6. self.name = name
    7. self.age = age
    8. @property
    9. def name(self):
    10. return self._name
    11. @name.setter
    12. def name(self, value):
    13. if not isinstance(value, str):
    14. raise TypeError('name must be a string')
    15. self._name = value
    16. @property
    17. def age(self):
    18. return self._age
    19. @age.setter
    20. def age(self, value):
    21. if not isinstance(value, int):
    22. raise TypeError('age must be an int')
    23. self._age = value
    24. p = Person('Ming', 19)
    25. print(p.name) # Ming
    26. print(p.age) # 19
    27. # 可以看到,为了实现属性值的类型检查我们写了很多的重复代码。 只要你以后看到类似这样的代码,你都应该想办法去简化它。 一个可行的方法是创建一个函数用来定义属性并返回它。例如:
    28. def typed_property(name, expected_type):
    29. storage_name = '_' + name
    30. @property
    31. def prop(self):
    32. return getattr(self, storage_name)
    33. @prop.setter
    34. def prop(self, value):
    35. if not isinstance(value, expected_type):
    36. raise TypeError('{} must ne a {}'.format(name, expected_type))
    37. setattr(self, storage_name, value)
    38. return prop
    39. class Person:
    40. name = typed_property('name', str)
    41. age = typed_property('age', int)
    42. def __init__(self, name, age):
    43. self.name = name
    44. self.age = age
    45. p = Person('Yong', 18)
    46. print(p.name) # Yong
    47. print(p.age) # 18
    48. p.age = 20
    49. print(p.age) # 20
    50. # 本节我们演示内部函数或者闭包的一个重要特性,它们很像一个宏。例子中的函数 typed_property() 看上去有点难理解,其实它所做的仅仅就是为你生成属性并返回这个属性对象。 因此,当在一个类中使用它的时候,效果跟将它里面的代码放到类定义中去是一样的。 尽管属性的 getter 和 setter 方法访问了本地变量如 name , expected_type 以及 storate_name ,这个很正常,这些变量的值会保存在闭包当中。
    51. # 我们还可以使用 functools.partial() 来稍稍改变下这个例子,很有趣。例如,你可以像下面这样:
    52. from functools import partial
    53. String = partial(typed_property, expected_type=str)
    54. Integer = partial(typed_property, expected_type=int)
    55. # Example:
    56. class Person:
    57. name = String('name')
    58. age = Integer('age')
    59. def __init__(self, name, age):
    60. self.name = name
    61. self.age = age