__slots__通过限制实例属性并避免创建__dict__来优化内存,适用于属性固定且对象数量庞大的场景,能显著减少内存占用,但会失去动态添加属性的能力,且影响弱引用和继承行为,实际效果需通过sys.getsizeof()和timeit等工具测量评估。

Python中的
__slots__
__dict__
当我们定义一个类时,Python默认会给每个实例一个
__dict__
__slots__
__slots__
__dict__
比如,我们有一个表示二维点的类:
class PointWithoutSlots:
def __init__(self, x, y):
self.x = x
self.y = y
class PointWithSlots:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y用
sys.getsizeof()
PointWithSlots
PointWithoutSlots
__dict__
__slots__
立即学习“Python免费学习笔记(深入)”;
但要记住,一旦你用了
__slots__
PointWithSlots
z
p.z = 3
AttributeError
__slots__
我觉得这个问题问得非常好,因为它直接指向了
__slots__
__slots__
举个例子,如果你正在开发一个游戏,每个游戏角色、道具、地图块都可能是一个对象,这些对象成千上万,甚至几十万个。每个对象如果都带一个
__dict__
__slots__
再比如,处理大量数据记录的场景,比如一个ORM(对象关系映射)框架,将数据库中的每一行数据映射成一个Python对象。如果你的数据库表有几百万行,而每个数据行对象只包含固定的几个字段,那么
__slots__
当然,这不是说所有类都应该用
__slots__
__slots__
__slots__
嗯,天下没有免费的午餐,
__slots__
首先,最明显的就是实例不能再动态添加新属性了。一旦你定义了
__slots__
__slots__
obj.new_attr = value
AttributeError
其次,实例将不再拥有__dict__
obj.__dict__
vars(obj)
__slots__
'__dict__'
__slots__
再者,默认情况下,实例也不能被弱引用(weak reference)。如果你需要弱引用功能,就必须把
'__weakref__'
__slots__
__dict__
继承关系上,
__slots__
__slots__
__dict__
__slots__
__slots__
__slots__
__slots__
__slots__
__slots__
最后,我觉得还有一点,虽然不算是严格意义上的副作用,但值得一提:它可能会稍微增加代码的“僵硬度”。因为它限制了灵活性,你在设计类的时候就需要更深思熟虑,提前规划好所有可能的属性。这对于快速原型开发或者需求经常变动的项目来说,可能不是最好的选择。
__slots__
评估
__slots__
1. 内存占用评估:
最直观的方法就是使用
sys.getsizeof()
__slots__
__slots__
import sys
class NoSlots:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
class WithSlots:
__slots__ = ('name', 'age', 'city')
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
ns_obj = NoSlots("Alice", 30, "New York")
ws_obj = WithSlots("Bob", 25, "London")
print(f"NoSlots object size: {sys.getsizeof(ns_obj)} bytes")
print(f"WithSlots object size: {sys.getsizeof(ws_obj)} bytes")
# 注意:sys.getsizeof()只计算对象本身的内存,不包括它引用的其他对象的内存。
# 对于字符串等不可变对象,它们可能在内存中只存一份。
# 但对于__dict__的开销,它是很准确的。要更全面地评估,特别是当你创建了大量对象时,可以考虑使用像
pympler
memory_profiler
__slots__
2. 性能(属性访问速度)评估:
使用
timeit
__slots__
import timeit
setup_code = """
class NoSlots:
def __init__(self, x, y):
self.x = x
self.y = y
class WithSlots:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
ns_obj = NoSlots(1, 2)
ws_obj = WithSlots(1, 2)
"""
# 测试属性读取
time_ns_read = timeit.timeit("ns_obj.x", setup=setup_code, number=1_000_000)
time_ws_read = timeit.timeit("ws_obj.x", setup=setup_code, number=1_000_000)
print(f"NoSlots attribute read time: {time_ns_read:.4f} seconds")
print(f"WithSlots attribute read time: {time_ws_read:.4f} seconds")
# 测试属性写入
time_ns_write = timeit.timeit("ns_obj.x = 3", setup=setup_code, number=1_000_000)
time_ws_write = timeit.timeit("ws_obj.x = 3", setup=setup_code, number=1_000_000)
print(f"NoSlots attribute write time: {time_ns_write:.4f} seconds")
print(f"WithSlots attribute write time: {time_ws_write:.4f} seconds")通常情况下,
__slots__
__dict__
3. 综合考量:
最终的决策,我觉得还是要回到你的具体应用场景。如果内存是瓶颈,而且对象数量巨大,
__slots__
__dict__
__slots__
以上就是Python中的__slots__有什么作用?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号