python的__slots__

 It involves the usage of __slots__ to tell Python not to use a dict, and only allocate space for a fixed set of attributes.

WITH __slots__ :

>>> class test_slots(object):
	__slots__ = ('x','y')

	
>>> class test(object):
	pass

>>> ts = test_slots()
>>> t = test()
>>> print(dir(ts))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'x', 'y']
>>> print(dir(t))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']


>>> class Student(object):
	__slots__ = ('name', 'age')
	def set_name(self, str): #function name is not in __slots__ 
		self.name = str

		
>>> s = Student()
>>> s.set_name('Michael')
>>> s.name
'Michael'
>>> s.age = 25
>>> print(dir(s))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'age', 'name', 'set_name']
>>> print(dir(Student))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'age', 'name', 'set_name']

注意: 继承链中如果哪一级少了 __slots__ 属性实现,子类中的 __slots__ 失效(y因为父类含有__dict__)
>>> class Person(object):
	pass

>>> class Student(Person):
	__slots__ = ('name', 'age')

	
>>> s = Student()
>>> s.sss = 9
>>> s.sss
9
>>> dir(s)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'sss']
>>> dir(Person)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> dir(Student)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']
>>> s.__slots__
('name', 'age')
>>> s.__dict__
{'sss': 9}



???:__slots__限制通过实例添加属性(变量 and 函数),但仍然可通过类(给所有实例)添加 变量 and 函数, 但这种 类变量 不能通过实例s修改(仅可通过Student.score修改)
>>> class Student(object):
	__slots__ = ('name', 'age')
	def set_name(self, str):
		self.name = str

		
>>> from types import MethodType
>>> def set_age(self, age):
	self.age = age

	
>>> s = Student()
>>> s.set_age = MethodType(set_age, s)       #不能给单个实例绑定函数
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    s.set_age = MethodType(set_age, s)
AttributeError: 'Student' object has no attribute 'set_age'
>>> Student.set_age = set_age           #可以通过类(所有实例)绑定函数
>>> print(dir(Student))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'age', 'name', 'set_age', 'set_name']
>>> print(dir(s))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'age', 'name', 'set_age', 'set_name']
>>> s.set_age(25)
>>> s.age
25
>>> Student.score = 99   #可以通过类增加类变量
>>> print(dir(Student))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'age', 'name', 'score', 'set_age', 'set_name']
>>> s.score = 90
Traceback (most recent call last):
  File "<pyshell#25>", line 1, in <module>
    s.score = 90
AttributeError: 'Student' object attribute 'score' is read-only #但不可通过实例修改
>>> print(dir(s))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'age', 'name', 'score', 'set_age', 'set_name']





>>> class Student(object):
	__slots__ = ('name', 'age')
	def set_name(self, str):
		self.name = str

		
>>> from types import MethodType
>>> def set_score(self, num):
	self.score = num

	
>>> s = Student()
>>> s.set_score = MethodType(set_score, s)
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    s.set_score = MethodType(set_score, s)
AttributeError: 'Student' object has no attribute 'set_score'
>>> Student.set_score = set_score
>>> s.set_score(60)
Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    s.set_score(60)
  File "<pyshell#6>", line 2, in set_score
    self.score = num
AttributeError: 'Student' object has no attribute 'score' #但score属性不存在
>>> print(dir(s))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'age', 'name', 'set_name', 'set_score']
>>> s.set_score
<bound method set_score of <__main__.Student object at 0x02A98A90>>


WITHOUT __slots__:

>>> class test(object):
	pass

>>> from types import MethodType
>>> t = test()
>>> def set_num(self, num):
	self.num = num

	
>>> t.set_num = MethodType(set_num, t)
>>> t.set_num(99)
>>> t.num
99
>>> print(dir(t))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'num', 'set_num']
>>> print(dir(test))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']




转自https://www.python-course.eu/python3_slots.php:

The attributes of objects are stored in a dictionary "__dict__". Like any other dictionary, a dictionary used for attribute storage doesn't have a fixed number of elements. In other words, you can add elements to dictionaries after they have been defined, as we have seen in our chapter on dictionaries. This is the reason, why you can dynamically add attributes to objects of classes that we have created so far: 

>>> class A(object):
...     pass
... 
>>> a = A()
>>> a.x = 66
>>> a.y = "dynamically created attribute"
The dictionary containing the attributes of "a" can be accessed like this:
>>> a.__dict__
{'y': 'dynamically created attribute', 'x': 66}
You might have wondered that you can dynamically add attributes to the classes, we have defined so far, but that you can't do this with built-in classes like 'int', or 'list':
>>> x = 42
>>> x.a = "not possible to do it"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'a'
>>> 
>>> lst = [34, 999, 1001]
>>> lst.a = "forget it"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'a'
Using a dictionary for attribute storage is very convenient, but it can mean a waste of space for objects, which have only a small amount of instance variables. The space consumption can become critical when creating large numbers of instances. Slots are a nice way to work around this space consumption problem. Instead of having a dynamic dict that allows adding attributes to objects dynamically, slots provide a static structure which prohibits additions after the creation of an instance. 

When we design a class, we can use slots to prevent the dynamic creation of attributes. To define slots, you have to define a list with the name __slots__. The list has to contain all the attributes, you want to use. We demonstrate this in the following class, in which the slots list contains only the name for an attribute "val". 
class S(object):

    __slots__ = ['val']

    def __init__(self, v):
        self.val = v


x = S(42)
print(x.val)

x.new = "not possible"
If we start this program, we can see, that it is not possible to create dynamically a new attribute. We fail to create an attribute "new":
42
Traceback (most recent call last):
  File "slots_ex.py", line 12, in <module>
    x.new = "not possible"
AttributeError: 'S' object has no attribute 'new'

We mentioned in the beginning that slots are preventing a waste of space with objects. Since Python 3.3 this advantage is not as impressive any more. With Python 3.3 Key-Sharing Dictionaries are used for the storage of objects. The attributes of the instances are capable of sharing part of their internal storage between each other, i.e. the part which stores the keys and their corresponding hashes. This helps to reduce the memory consumption of programs, which create many instances of non-builtin types.



廖雪峰教程:

使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:

>>> class GraduateStudent(Student):
...     pass
...
>>> g = GraduateStudent()
>>> g.score = 9999

除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__





http://blog.csdn.net/sxingming/article/details/52892640

http://blog.csdn.net/sxingming/article/details/52900530


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值