python的slots_
正常情况下,当我们定义了一个 class
,创建了一个 class
的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。
但是,如果我们想要限制实例的属性怎么办?比如,只允许对 Student
实例添加 name
和 score
属性。
为了达到限制的目的,Python 允许在定义 class
的时候,定义一个特殊的 __slots__
变量,来限制该 class
实例能添加的属性:
class Student(object):
__slots__ = ('name', 'score')
def __init__(self, name, score):
self.name = name
self.score = score
测试一下:
>>> bart.score = 99
>>> bart.score
99
>>> bart = Student('bart', 60)
>>> bart.age = 12
......
AttributeError: 'Student' object has no attribute 'age'
由于 'age'
没有被放到 __slots__
中,所以不能绑定 age
属性,试图绑定 age
将得到 AttributeError
的错误。
使用 __slots__
要注意,__slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。
除非在子类中也定义 __slots__
,这样,子类实例允许定义的属性就是自身的 __slots__
加上父类的 __slots__
。
使用property()和@property的区别
取值和赋值
class Actress():
def __init__(self):
self.name = 'TianXin'
self.age = 5
类Actress
中有两个成员变量name
和age
。在外部对类的成员变量的操作,主要包括取值和赋值。简单的取值操作是x=object.var
,简单的赋值操作是object.var=value
。
>>> actress = Actress()
>>> actress.name #取值操作
'TianXin'
>>> actress.age #取值操作
20
>>> actress.name = 'NoName' #赋值操作
>>> actress.name
'NoName'
使用 Getter 和 Setter
上述简单的取值和赋值操作,在某些情况下是不能满足要求的。比如,如果要限制Actress
的年龄范围,那么只使用上述简单的赋值操作就不能满足要求了。getter
和setter
实现这样的要求。
class Actress():
def __init__(self):
self._name = 'TianXin'
self._age = 20
def getAge(self):
return self._age
def setAge(self, age):
if age > 30:
raise ValueError
self._age = age
调用setAge
函数可以实现将变量_age
的取值范围限制到小于30.
>>> actress = Actress()
>>> actress.setAge(28)
>>> actress.getAge()
28
>>> actress.setAge(35)
ValueError
使用property
property的定义是
class property(object)
property(fget=None, fset=None, fdel=None, doc=None) -> property attributefget 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也实现上述对成员变量的取值限制。
class Person:
def __init__(self):
self.__name= None
#这是setter方法
def setName(self,name):
self.__name=name
#这是getter方法
def getName(self ):
return self.__name
name_value=property(getName,setName) #名字可以随便去,这里使用name_value是为了直观,直接用一个n命名更简单
p = Person() #实例化
p.name_value = 'chb' #直接赋值,这行代码等同于 p.setName('chb')
n = p.name_value #直接读取数据 ,等同于使用 p.getName()
print(n) #输出结果:chb
这种方法就是在写好了setteer和getter后,加上一句property函数赋值代码。property函数结构为property(fget=None,fset=None,fdel=None,doc=None),可以看出property可以再一个deleter,上面代码中没有加。如果加上,deleter写法代码如下:
#这是deleter
def delName(self):
del self.__name
然后property赋值语句变为:
name_value=property(getName,setName,delName)
使用方法为:
del p.name_value
print(p.name_value) #运行会出错
这种方法的好处是你可以按照原来的方法写getter和setter,连getter和setter的函数名都可以不用改,只需要写完getter和setter是加一条property赋值语句。
使用@property
使用@property同样可以实现上述类的定义。
class Actress():
def __init__(self):
self._name = 'TianXin'
self._age = 20
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age > 30:
raise ValueError
self._age = age
使用时的示例:
>>> actress = Actress()
>>> actress.age
20
>>> actress.age = 18
>>> actress.age = 45
ValueError