Python slots 的用法笔记
Python 是一个动态语言,可以动态的给实例或类增减属性或方法,给类添加的属性会影响到前后所有创建的实例。但是使用
在使用
我们来看下面的例子
类或实例可以随意的添加属性和方法
如果我们引入
引入了
但是定义类时声明的方法不在
在
声明的没定义在
但是声明在没定义在
定义在
另外,用
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
__slots__ 属性可以限定类或实例属性和方法,如果没有 __slots__ 的话实例的属性和方法包含在实例的 __dict__ 字典中,类的属性和方法包含在类的 __dict__ 字典中。在使用
__slots__ 按常规写法可能会出现的问题大概有- AttributeError: 'Xxx' object has no attribute 'yyy'
- AttributeError: 'Xxx' object attribute 'yyy' is read-only
- ValueError: 'yyy' in __slots__ conflicts with class variable
我们来看下面的例子
1>>> class Cat:
2... lags = 4
3... def __init__(self):
4... self.eyes = 2
5...
6... def walk(self):
7... pass
8...
9...
10>>> Cat.__dict__
11mappingproxy({'__module__': '__main__', 'lags': 4, '__init__': <function Cat.__init__ at 0x106816700>, 'walk': <function Cat.walk at 0x106817920>, '__dict__': <attribute
12'__dict__' of 'Cat' objects>, '__weakref__': <attribute '__weakref__' of 'Cat' objects>, '__doc__': None})
13>>> c1 = Cat()
14>>> c1.__dict__
15{'eyes': 2}
16>>> c1.miaow = lambda: 'hello'
17>>> c1.__dict__
18{'eyes': 2, 'miaow': <function <lambda> at 0x106d6fce0>}
19>>> Cat.ears = 2
20>>> c1.ears
212
22>>> c1.__dict__
23{'eyes': 2, 'miaow': <function <lambda> at 0x106d6fce0>}
24>>> Cat.__dict__
25mappingproxy({'__module__': '__main__', 'lags': 4, '__init__': <function Cat.__init__ at 0x106816700>, 'walk': <function Cat.walk at 0x106817920>, '__dict__': <attribute
26'__dict__' of 'Cat' objects>, '__weakref__': <attribute '__weakref__' of 'Cat' objects>, '__doc__': None, '__getattribute__': <slot wrapper '__getattribute__' of 'object'
27 objects>, 'ears': 2})类或实例可以随意的添加属性和方法
如果我们引入
__slots__ 来限定属性或方法 1>>> class Cat:
2... __slots__ = ('lags', 'eyes')
3... def __init__(self):
4... self.eyes = 2
5...
6...
7...
8>>> Cat.__dict__
9mappingproxy({'__module__': '__main__', '__slots__': ('lags', 'eyes'), '__init__': <function Cat.__init__ at 0x10699ef20>, 'eyes': <member 'eyes' of 'Cat' objects>, 'lags
10': <member 'lags' of 'Cat' objects>, '__doc__': None})
11>>> c1 = Cat()
12>>> c1.__dict__
13Traceback (most recent call last):
14 File "<input>", line 1, in <module>
15 c1.__dict__
16AttributeError: 'Cat' object has no attribute '__dict__'
17>>> c1.lags
18Traceback (most recent call last):
19 File "<input>", line 1, in <module>
20 c1.lags
21AttributeError: 'Cat' object has no attribute 'lags'
22>>> c1.eyes
232
24>>> c1.lags = 4
25>>> c1.ears = 2
26Traceback (most recent call last):
27 File "<input>", line 1, in <module>
28 c1.ears = 2
29 ^^^^^^^
30AttributeError: 'Cat' object has no attribute 'ears'
31>>> c1.miaow = lambda: 'hello'
32Traceback (most recent call last):
33 File "<input>", line 1, in <module>
34 c1.miaow = lambda: 'hello'
35 ^^^^^^^^
36AttributeError: 'Cat' object has no attribute 'miaow'
37>>> c1.lags = lambda: 'hello'
38>>> c1.lags
39<function <lambda> at 0x106d6c7c0>引入了
__slots__ 后实例不再有 __dict__ 属性,只能添加在 __slots__ 中列出的属性或方法。添加没在 __slots__ 中的属性或方法时会报错误AttributeError: 'Xxx' object has no attribute 'yyy'在初始化函数中
__init__(self) 中也是一样的,如 1>>> class Cat:
2... __slots__ = ('lags', 'eyes')
3... def __init__(self):
4... self.ears = 2
5...
6...
7...
8>>> c1 = Cat()
9Traceback (most recent call last):
10 File "<input>", line 1, in <module>
11 c1 = Cat()
12 ^^^^^
13 File "<input>", line 4, in __init__
14 self.ears = 2
15 ^^^^^^^^^
16AttributeError: 'Cat' object has no attribute 'ears'__slots__ 中没有 ears, 所以不能在初始化方法或外部动态添加该属性但是定义类时声明的方法不在
__slots__ 约束内1>>> class Cat:
2... __slots__ = ('lags', 'eyes')
3... def walk(self):
4... pass
5...
6...
7>>> c1 = Cat()
8>>> c1.walk()__slots__ 也不约束通过类动态添加属性或方法1>>> class Cat:
2... __slots__ = ('lags', 'eyes')
3...
4...
5>>> Cat.ears = 2
6>>>在
__slots__ 中不能包含类变量,比如1>>> class Cat:
2... __slots__ = ('lags')
3... lags = 4
4...
5...
6Traceback (most recent call last):
7 File "<input>", line 1, in <module>
8 class Cat:
9ValueError: 'lags' in __slots__ conflicts with class variable声明的没定义在
__slots__ 中的类变量对实例方法是只读的 1>>> class Cat:
2... __slots__ = ('lags')
3... eyes = 2
4... def __init__(self):
5... self.eyes = 3
6...
7...
8...
9>>> c1 = Cat()
10Traceback (most recent call last):
11 File "<input>", line 1, in <module>
12 c1 = Cat()
13 ^^^^^
14 File "<input>", line 5, in __init__
15 self.eyes = 3
16 ^^^^^^^^^
17AttributeError: 'Cat' object attribute 'eyes' is read-only但是声明在没定义在
__slots__ 中的类变量通过实例来修改也不行,但可以通过类属性来修改 1>>> class Cat:
2... __slots__ = ('lags')
3... eyes = 2
4...
5...
6>>> c1 = Cat()
7>>> c1.eyes = 3
8Traceback (most recent call last):
9 File "<input>", line 1, in <module>
10 c1.eyes = 3
11 ^^^^^^^
12AttributeError: 'Cat' object attribute 'eyes' is read-only
13>>> Cat.eyes = 3
14>>> c1.eyes
153定义在
__slots__ 中的属性或方法在 IDE 中会有智能提示。__slots__ 只能作用在当前类中,不会影响到子类,子类需定义自己的 __slots__. 1>>> class Animal:
2... __slots__ = ('lags')
3...
4...
5>>> class Cat(Animal):
6... pass
7...
8>>> Animal.__slots__
9'lags'
10>>> Cat.__slots__
11'lags'
12>>> c = Cat()
13>>> c.eyes = 2__slots__ 对于实例是只读的,通过类的 __slots__ 属性可修改,但不改变原有的约束 1>>> class Cat:
2... __slots__ = ('lags', 'eyes')
3...
4...
5>>> c.__slots__ = ('lags', 'eyes', 'ears')
6Traceback (most recent call last):
7 File "<input>", line 1, in <module>
8 c.__slots__ = ('lags', 'eyes', 'ears')
9 ^^^^^^^^^^^
10AttributeError: 'Cat' object attribute '__slots__' is read-only
11>>> Cat.__slots__ = ('lags', 'eyes', 'ears')
12>>> c = Cat()
13>>> c.ears = 2
14Traceback (most recent call last):
15 File "<input>", line 1, in <module>
16 c.ears = 2
17 ^^^^^^
18AttributeError: 'Cat' object has no attribute 'ears'
19>>> c.__slots__
20('lags', 'eyes', 'ears')
21>>> Cat.__slots__
22('lags', 'eyes', 'ears')__slots__ 还可声明为 list, 或省略圆括号的 tuple 形式 1>>> class Cat:
2... __slots__ = ['lags', 'eyes']
3...
4...
5>>> class Cat:
6... __slots__ = 'lags', 'eyes'
7...
8...
9>>> type(Cat.__slots__)
10<class 'tuple'>另外,用
__slots__ 避免了使用 __dict__ 记录实例属性和方法,可节约一些内存
永久链接 https://yanbin.blog/python-__slots__-notes/, 来自 隔叶黄莺 Yanbin's Blog[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。