1. __slots__ : 申明允许赋予给实例的属性
Python默认用字典__dict__来保存类的实例属性,这会占用大量的空间。
使用__slots__后,Python不会再建立字典,只给一个slots声明的属性分配空间。
当一个类需要创建大量实例时,可以通过__slots__声明实例所需要的属性,以减小内存占用。
1.1 先看看没有__slots__的情况
class Teacher(object):
def __init__(self, name='saolaoshi', age=21, number='158xxxx1234'):
self.name = name
self.age = age
self.number = number
def say_hello(self):
print('hello', name, '!')
# 创建实例sls
sls = Teacher(name='saolaoshi')
# 打印sls的属性
print(sls.__dict__)
运行结果:
{‘name’: ‘saolaoshi’, ‘age’: 21, ‘number’: ‘158xxxx1234’}
我们给sls添加一些新的属性
sls.hair_curl = 'permanent wave'
sls.hair_color = 'darkblue'
# 再打印结果
print(sls.__dict__)
运行结果:
{‘name’: ‘saolaoshi’, ‘age’: 21, ‘number’: ‘158xxxx1234’, ‘hair_curl’: ‘permanent wave’, ‘hair_color’: ‘darkblue’}
看,还是可以绑新的属性给sls的。
1.2 加入__slots__
class Teacher(object):
__slots__ = ('name', 'age', 'number', 'hair_color')
def __init__(self, name='saolaoshi', age=21, number='158xxxx1234'):
self.name = name
self.age = age
self.number = number
def say_hello(self):
print('hello', name, '!')
sls = Teacher()
print(sls.__dict__) # 结果1
sls.hair_color = 'darkblue' # 结果2
sls.hair_curl = 'permanent wave' # 结果2
运行结果:
- 确实,有__slots__无__dict__。
2. 只能添加hair_color属性,没有hair_curl属性。
2 @property:属性校验
对于Teacher()类,我们希望属性name的type为str,age为 0~100 的int。
在建立每一个实例的时候,都应该对属性进行校验,合格则允许创建,不合格则进行提示。
2.1 用描述符__get__和__set__以及__delete__
- __get__():调用一个属性时,触发
- __set__():为一个属性赋值时,触发
- __delete__():采用del删除属性时,触发
还是以Teacher类为例:
"""定义一个Teacher类,假设它只有一个属性name,而name用包含描述符的Name类代理"""
class Name:
def __get__(self, instance, owner):
print('调用属性')
print(instance, '\n', owner)
def __set__(self, instance, value):
print('设置属性')
print(instance, '\n', value)
def __delete__(self, instance):
print('删除属性')
print(instance)
class Teacher(object):
name = Name() # 这时候,name属性由Name类来代理
def __init__(self, name):
self.name = name
"""进行三次测试"""
sls = Teacher(name='saolaoshi') # 结果1
sls.name # 结果2
del sls.name # 结果3
运行结果:
- 设置属性
<__main__.Teacher object at 0x7feff1332550>
saolaoshi- 调用属性
<__main__.Teacher object at 0x7feff1332550>
<class ‘__main__.Teacher’>- 删除属性
<__main__.Teacher object at 0x7feff1332550>
2.2 用@property装饰器
@property的作用是:把方法变成属性调用,保证对参数进行必要的检查
还是比如,我们有一个Teacher类,在里面要保证name是str
class Teacher(object):
def __init__(self, name='Youlaoshi', age='21'):
self._name = name # 注意:self的属性是_name,成员方法是name()
self.age = age
# 读取传进来的参数name,相当于__get__
@property
def name(self):
print('读取')
print(self._name)
return self._name
# 进行设置,相当于__set__
@name.setter
def name(self, value):
print('设置')
print(value)
if isinstance(value, str):
self._name = value
else:
raise ValueError("'str' type needed")
# 进行删除,相当于__delete__
@name.deleter
def name(self):
print('删除')
del self._name
sls = Teacher()
"""进行三次测试"""
sls.name # 结果1
sls.name = 'Saolaoshi' # 结果2
del sls.name # 结果3
运行结果
- 读取
Youlaoshi- 设置
Saolaoshi- 删除
注意:
- 在最开始init的时候,self的属性名是_name,方法名是name()
- 当我们在外部对属性进行操作的时候,是调用的name方法名进行操作,而非属性
- @property需要在@x.setter和@x.deleter前面,只有@property的时候是只读属性
注:若在使用的时候忘记了语法,可以help(property)