动态语言:可以在运行的过程中,修改代码
静态语言:编译时已经确定好代码,运行过程中不能修改
如果我们想要限制实例的属性怎么办?比如,只允许对Person实例添加name和age属性。
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__
变量,来限制该class实例能添加的属性。注意:使用__slots__
要注意,__slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
__slots__
的作用:
- 指明对象可以绑定的属性,限制对象任意绑定属性
- 节省内存空间,每个对象都有
__dict__
属性,该字典存放着属性与值的映射关系。使用slots可以省去这个字典
1.绑定属性
class Foo(object):
__slots__ = ("name", "age")
def __init__(self):
self.name = 'book'
self.age = 18
self.email = 'abc@qq.com'
foo = Foo()
输出
Traceback (most recent call last):
File "/Users/Liang/Documents/PyProject/demo1.py", line 11, in <module>
foo = Foo()
File "/Users/Liang/Documents/PyProject/demo1.py", line 7, in __init__
self.email = 'abc@qq.com'
AttributeError: 'Foo' object has no attribute 'email'
2.节省内存
在默认情况下,Python的新类和旧类的实例都有一个字典__dict__
来存储属性值。这对于那些没有实例属性的对象来说太浪费空间了,当需要创建大量实例的时候,这个问题变得尤为突出(Python内置的字典本质是一个哈希表,它是一种用空间换时间的数据结构。为了解决冲突的问题,当字典使用量超过2/3时,Python会根据情况进行2-4倍的扩容。由此可预见,取消__dict__
的使用可以大幅减少实例的空间消耗。)。因此这种默认的做法可以通过在新式类中定义了一个__slots__
属性从而得到了解决。__slots__
声明中包含若干实例变量,并为每个实例预留恰好足够的空间来保存每个变量,因此没有为每个实例都创建一个字典,从而节省空间。以下是用元祖来存储实例属性,这样Python会在实例中使用类似元祖的结构存储实例变量。
class Foo1(object):
__slots__ = ("name", "age") # 也可以用列表存储
def __init__(self):
self.name = 'book'
self.age = 18
class Foo2(object):
def __init__(self):
self.name = 'book'
self.age = 18
foo1 = Foo1()
foo2 = Foo2()
print(dir(foo1)) # 没有__dict__属性
print(dir(foo2))
3.slots的副作用
- 每个继承的子类都要重新定义一遍
__slots__
- 实例只能包含哪些在
__slots__
定义的属性,这对写程序的灵活性有影响,比如你由于某个原因新网给instance设置一个新的属性,比如instance.a = 1, 但是由于a不在__slots__
里面就直接报错了,你得不断地去修改__slots__
或者用其他方法迂回的解决 - 实例不能有弱引用(weakref)目标,否则要记得把
__weakref__
放进__slots__
网友评论