某公司一面中给出一段代码:
class Student():
def __init__(self, name):
print "Student inti"
super(Student, self).__init__(name)
if __name__ == "__main__":
s1 = Student("XIAOMIN")
s1.english =90
要求可以使用s1.english =90的方式直接访问变量,但是需要对变量值做限制(0-100间的整数);又要防止输入错误添加新的不合法的变量进去(如english 错误的写为englash ),如何实现?
答案:使用__slots__进行变量限制,使用装饰器@property进行变量控制:
# coding=utf-8
__author__ = 'Wang'
class Person(object):
__slots__ = ('_name', '_age', '_sex') ##限制基类变量只能有这三个属性,实例对象无法增加新的属性,这就防止了用户误输入
def __init__(self, name):
self._name = name
print "Person init"
class Student(Person):
__slots__ = ('_grade', '_english', '_chinese')##限制基类变量只能有这三个属性,实例对象无法增加新的属性,这就防止了用户误输入
def __init__(self, name):
print "Student inti"
# Person.__init__(self, name)
super(Student, self).__init__(name)
@property ##property 方法访问变量
def english(self):
return self._english
@english.setter ##property 方法设置变量,这里面对参数进行了校验
def english(self, value):
if not isinstance(value, int):
raise ValueError('分数必须是整数才行呐')
if value < 0 or value > 100:
raise ValueError('分数必须0-100之间')
self._english = value
if __name__ == "__main__":
s1 = Student("XIAOMIN")
s1._english =90 ####正常执行,不使用装饰器直接设置变量
s1.english =90 ####正常执行,使用装饰器直接设置变量
s1.englash =90 ####不能正常执行,AttributeError: 'Student' object has no attribute 'englash'
s1._englash =90 ####不能正常执行,AttributeError: 'Student' object has no attribute '_englash
s1._english =90.5 ####正常执行,不使用装饰器直接设置变量可以设置成浮点数
s1.english =90.5 #####不能正常执行,引发ValueError
另外可以使用内建函数__setattr__来对变量赋值
s1.__setattr__('_english', 90) ###直接访问变量,没有经过装饰器函数
s1.__setattr__('english', 90.5) ###执行失败,经过装饰器函数校验
print s1.__getattribute__('_english')
s1.__setattr__('_englaash', 90) #####不能正常执行,AttributeError
知识点1:
1) __slots__限制实例随意增加属性,而__setattr__内建函数则不允许访问不存在的属性
2) __slots__使对__dict__的替代,存在__slots__的类不存在__dict__,访问是s1.__dict__会引发AttributeError
3)执行vars(s1)会引发TypeError,vars()内建函数与dir()类似,但是必须要求实例中包含__dict__
4) __dict__属性跟踪所有的实例属性,返回的是一个字典,占用内存较多,基于内存考虑的话可以用__slots__代替__dict__
知识点2:
看一下实例和变量的__dict__属性,包含哪些内容:
class anmon(object):
'''
this is doc.
'''
def __init__(self, name):
self._name = name
print "anmon init"
def anon_a(self):
self.anon_a = 'aaaa'
if __name__ == "__main__":
print anmon.__dict__
a2 = anmon('xiaoli')
print a2.__dict__
a2.anon_a()
print a2.__dict__
{'__module__': '__main__', 'anon_a': <function anon_a at 0x0000000002DC9048>, '__dict__': <attribute '__dict__' of 'anmon' objects>, '__weakref__': <attribute '__weakref__' of 'anmon' objects>, '__doc__': '\n this is doc.\n ', '__init__': <function __init__ at 0x0000000002DC3F98>}
anmon init
{'_name': 'xiaoli'} #####print a2.__dict__
{'anon_a': 'aaaa', '_name': 'xiaoli'} #####执行完anon_a()再次执行print a2.__dict__多了一个变量
知识点3:
使用dir查看类和实例
class anmon(object):
'''
this is doc.
'''
def __init__(self, name):
self._name = name
print "anmon init"
def anon_a(self):
self.anon_a = 'aaaa'
if __name__ == "__main__":
a2 = anmon('xiaoli')
print dir(anmon)
print dir(a2)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'anon']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_name', 'anon']
1)都包含了内建函数、内建属性和定义的方法名称
2)实例的dir中多了init中定义的变量_name,但不包含普通方法中定义的anon_a