python的slots_

正常情况下,当我们定义了一个 class,创建了一个 class 的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。

但是,如果我们想要限制实例的属性怎么办?比如,只允许对 Student 实例添加 namescore属性。

为了达到限制的目的,Python 允许在定义 class 的时候,定义一个特殊的 __slots__ 变量,来限制该 class 实例能添加的属性:

  1. class Student(object):
  2. __slots__ = ('name', 'score')
  3. def __init__(self, name, score):
  4. self.name = name
  5. self.score = score

测试一下:

  1. >>> bart.score = 99
  2. >>> bart.score
  3. 99
  4. >>> bart = Student('bart', 60)
  5. >>> bart.age = 12
  6. ......
  7. AttributeError: 'Student' object has no attribute 'age'

由于 'age' 没有被放到 __slots__ 中,所以不能绑定 age 属性,试图绑定 age 将得到 AttributeError 的错误。

使用 __slots__ 要注意,__slots__ 定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。

除非在子类中也定义 __slots__,这样,子类实例允许定义的属性就是自身的 __slots__ 加上父类的 __slots__

使用property()和@property的区别

取值和赋值

  1. class Actress():
  2. def __init__(self):
  3. self.name = 'TianXin'
  4. self.age = 5

Actress中有两个成员变量nameage。在外部对类的成员变量的操作,主要包括取值和赋值。简单的取值操作是x=object.var,简单的赋值操作是object.var=value

  1. >>> actress = Actress()
  2. >>> actress.name #取值操作
  3. 'TianXin'
  4. >>> actress.age #取值操作
  5. 20
  6. >>> actress.name = 'NoName' #赋值操作
  7. >>> actress.name
  8. 'NoName'

使用 Getter 和 Setter

上述简单的取值和赋值操作,在某些情况下是不能满足要求的。比如,如果要限制Actress的年龄范围,那么只使用上述简单的赋值操作就不能满足要求了。gettersetter实现这样的要求。

  1. class Actress():
  2. def __init__(self):
  3. self._name = 'TianXin'
  4. self._age = 20
  5. def getAge(self):
  6. return self._age
  7. def setAge(self, age):
  8. if age > 30:
  9. raise ValueError
  10. self._age = age

调用setAge函数可以实现将变量_age的取值范围限制到小于30.

  1. >>> actress = Actress()
  2. >>> actress.setAge(28)
  3. >>> actress.getAge()
  4. 28
  5. >>> actress.setAge(35)
  6. ValueError

使用property

property的定义是

class property(object)
property(fget=None, fset=None, fdel=None, doc=None) -> property attribute

fget is a function to be used for getting an attribute value, and likewise, fset is a function for setting, and fdel a function for del’ing, an attribute. Typical use is to define a managed attribute x

其中,fget是取值函数,fset是赋值函数,fdel是删除函数。使用property也实现上述对成员变量的取值限制。

  1. class Person:
  2. def __init__(self):
  3. self.__name= None
  4. #这是setter方法
  5. def setName(self,name):
  6. self.__name=name
  7. #这是getter方法
  8. def getName(self ):
  9. return self.__name
  10. name_value=property(getName,setName) #名字可以随便去,这里使用name_value是为了直观,直接用一个n命名更简单
  11. p = Person() #实例化
  12. p.name_value = 'chb' #直接赋值,这行代码等同于 p.setName('chb')
  13. n = p.name_value #直接读取数据 ,等同于使用 p.getName()
  14. print(n) #输出结果:chb

这种方法就是在写好了setteer和getter后,加上一句property函数赋值代码。property函数结构为property(fget=None,fset=None,fdel=None,doc=None),可以看出property可以再一个deleter,上面代码中没有加。如果加上,deleter写法代码如下:

  1. #这是deleter
  2. def delName(self):
  3. del self.__name
  4. 然后property赋值语句变为:
  5. name_value=property(getName,setName,delName)
  6. 使用方法为:
  7. del p.name_value
  8. print(p.name_value) #运行会出错

这种方法的好处是你可以按照原来的方法写getter和setter,连getter和setter的函数名都可以不用改,只需要写完getter和setter是加一条property赋值语句。

使用@property

使用@property同样可以实现上述类的定义。

  1. class Actress():
  2. def __init__(self):
  3. self._name = 'TianXin'
  4. self._age = 20
  5. @property
  6. def age(self):
  7. return self._age
  8. @age.setter
  9. def age(self, age):
  10. if age > 30:
  11. raise ValueError
  12. self._age = age

使用时的示例:

  1. >>> actress = Actress()
  2. >>> actress.age
  3. 20
  4. >>> actress.age = 18
  5. >>> actress.age = 45
  6. ValueError