在Python中__slots__的目的是什么——特别是当我想要使用它时,什么时候不使用它?
当前回答
除了其他答案,这里还有一个使用__slots__的例子:
>>> class Test(object): #Must be new-style class!
... __slots__ = ['x', 'y']
...
>>> pt = Test()
>>> dir(pt)
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__',
'__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__slots__', '__str__', 'x', 'y']
>>> pt.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: x
>>> pt.x = 1
>>> pt.x
1
>>> pt.z = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute 'z'
>>> pt.__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__dict__'
>>> pt.__slots__
['x', 'y']
因此,要实现__slots__,它只需要额外的一行(并使您的类成为一个新样式的类,如果它还不是的话)。通过这种方式,您可以将这些类的内存占用减少5倍,代价是必须编写自定义pickle代码(如果需要的话)。
其他回答
除了其他答案,这里还有一个使用__slots__的例子:
>>> class Test(object): #Must be new-style class!
... __slots__ = ['x', 'y']
...
>>> pt = Test()
>>> dir(pt)
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__',
'__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__slots__', '__str__', 'x', 'y']
>>> pt.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: x
>>> pt.x = 1
>>> pt.x
1
>>> pt.z = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute 'z'
>>> pt.__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__dict__'
>>> pt.__slots__
['x', 'y']
因此,要实现__slots__,它只需要额外的一行(并使您的类成为一个新样式的类,如果它还不是的话)。通过这种方式,您可以将这些类的内存占用减少5倍,代价是必须编写自定义pickle代码(如果需要的话)。
Another somewhat obscure use of __slots__ is to add attributes to an object proxy from the ProxyTypes package, formerly part of the PEAK project. Its ObjectWrapper allows you to proxy another object, but intercept all interactions with the proxied object. It is not very commonly used (and no Python 3 support), but we have used it to implement a thread-safe blocking wrapper around an async implementation based on tornado that bounces all access to the proxied object through the ioloop, using thread-safe concurrent.Future objects to synchronise and return results.
默认情况下,对代理对象的任何属性访问都将为您提供代理对象的结果。如果你需要在代理对象上添加一个属性,可以使用__slots__。
from peak.util.proxies import ObjectWrapper
class Original(object):
def __init__(self):
self.name = 'The Original'
class ProxyOriginal(ObjectWrapper):
__slots__ = ['proxy_name']
def __init__(self, subject, proxy_name):
# proxy_info attributed added directly to the
# Original instance, not the ProxyOriginal instance
self.proxy_info = 'You are proxied by {}'.format(proxy_name)
# proxy_name added to ProxyOriginal instance, since it is
# defined in __slots__
self.proxy_name = proxy_name
super(ProxyOriginal, self).__init__(subject)
if __name__ == "__main__":
original = Original()
proxy = ProxyOriginal(original, 'Proxy Overlord')
# Both statements print "The Original"
print "original.name: ", original.name
print "proxy.name: ", proxy.name
# Both statements below print
# "You are proxied by Proxy Overlord", since the ProxyOriginal
# __init__ sets it to the original object
print "original.proxy_info: ", original.proxy_info
print "proxy.proxy_info: ", proxy.proxy_info
# prints "Proxy Overlord"
print "proxy.proxy_name: ", proxy.proxy_name
# Raises AttributeError since proxy_name is only set on
# the proxy object
print "original.proxy_name: ", proxy.proxy_name
插槽对于库调用非常有用,可以在进行函数调用时消除“命名方法分派”。SWIG文档中提到了这一点。对于想要减少常用调用函数的函数开销的高性能库来说,使用插槽要快得多。
这可能和OPs问题没有直接关系。它更多地与构建扩展有关,而不是与在对象上使用插槽语法有关。但它确实有助于完善插槽的使用情况以及它们背后的一些原因。
每个python对象都有一个__dict__属性,它是一个包含所有其他属性的字典。例如,当你输入self时。Attr python实际上正在执行self.__dict__[' Attr ']。你可以想象使用字典来存储属性需要一些额外的空间和时间来访问它。
然而,当你使用__slots__时,为该类创建的任何对象都不会有__dict__属性。相反,所有属性访问都直接通过指针完成。
所以如果你想要一个C风格的结构而不是一个完整的类,你可以使用__slots__来压缩对象的大小并减少属性访问时间。一个很好的例子是一个包含属性x和y的Point类。如果你要有很多点,你可以尝试使用__slots__来节省一些内存。
本质上,你没有使用__slots__。
当你认为你可能需要__slots__时,你实际上想要使用轻量级或Flyweight设计模式。在这些情况下,您不再希望使用纯Python对象。相反,您需要一个Python类对象的包装器来包装数组、结构体或numpy数组。
class Flyweight(object):
def get(self, theData, index):
return theData[index]
def set(self, theData, index, value):
theData[index]= value
类包装器没有属性——它只提供作用于底层数据的方法。方法可以简化为类方法。实际上,它可以简化为仅对底层数据数组进行操作的函数。
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录