Python描述符

现在试想一下我们有一个这样的场景。

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

我们希望在这里加入类型检查,name和gender都必须为字符串。

熟悉python的同学当然想到了property。那我们的代码就变成了这样子。

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

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

    @name.setter
    def name(self, name):
        if isinstance(name, str):
            self._name = name
        else:
            raise AttributeError('name must be a string !')

    @property
    def gender(self):
        return self._gender

    @gender.setter
    def gender(self, gender):
        if isinstance(gender, int):
            self._gender = gender
        else:
            raise AttributeError('gender must be a string !')

有没有发现一个很严重的问题,我们写了重复的逻辑,这样做是个十分不好的设计。我们希望自己写的类似于类型检查的逻辑可以复用。

下面就该我们描述符出场了,我们的代码变为了下面这样子。

class StringField:
    def __get__(self, instance, owner):
        return self.data

    def __set__(self, instance, value):
        if not isinstance(value, str):
            raise ValueError('need string !')
        self.data = value

    def __delete__(self):
        ...


class Person:
    name = StringField()
    gender = StringField()


if __name__ == '__main__':
    p = Person()
    p.name = 'Tom'
    print(p.name)
    p.name = 123

我们看一下输出结果。

Tom
Traceback (most recent call last):  File "/Users/shizhentao/PythonProjects/flask-demo/test.py", line 30, in 
    p.name = 123  File "/Users/shizhentao/PythonProjects/flask-demo/test.py", line 8, in __set__
    raise ValueError('need string !')
ValueError: need string !

跟上面的代码实现的效果一样,但是我们实现的十分精简。

你可能感兴趣的:(Python描述符)