gpt4 book ai didi

python - __slots__ 是如何工作的,你如何实现自己的?

转载 作者:太空宇宙 更新时间:2023-11-04 09:55:32 24 4
gpt4 key购买 nike

我一直在玩弄 __slots__ 并稍微搜索一下,但我仍然对某些细节感到困惑:

我知道 __slots__ 生成某种描述符:

>>> class C:
... __slots__ = ('x',)
...

>>> C.x
<member 'x' of 'C' objects>

>>> C.x.__get__
<method-wrapper '__get__' of member_descriptor object at 0x7f001de183a8>

>>> C.x.__get__
<method-wrapper '__get__' of member_descriptor object at 0x7f001de183a8>

但我想知道:这些值实际存储在哪里?

因为到目前为止我看到的描述符的常见配方/习语是:

>>> class Descr:
...
... def __init__(self, attrname):
... self.attrname = attrname
...
... def __get__(self, obj, cls):
... return obj.__dict__[self.attrname]
...
... def __set__(self, obj, val):
... obj.__dict__[self.attrname] = val
...
... class C:
...
... def __init__(self, x):
... self.x = x

__slots__一起使用时,有两个问题:

  1. 名字冲突:
>>> class C:
...
... __slots__ = ('x',)
...
... def __init__(self, x):
... self.x = x
...
... x = Descr('x')
...
Traceback (most recent call last)
...
ValueError: 'x' in __slots__ conflicts with class variable

因此,解决方法是将实际属性命名为“_x”。

  1. 没有 __dict__(除非您明确将其添加到 __slots__):
>>> class C:
...
... __slots__ = ('_x',)
...
... def __init__(self, x):
... self._x = x
...
... x = Descr('_x')
...

>>> c = C(0)

>>> c.x
Traceback (most recent call last)
...
AttributeError: 'C' object has no attribute '__dict__'

因此您必须改用 getattr()setattr()

您可以以通用描述符结束,该描述符可以与 __dict____slots__ 一起使用:

class WorksWithDictAndSlotsDescriptor:

def __init__(self, attr_name):
self.attr_name = attr_name

def __get__(self, instance, owner):
try:
return instance.__dict__[self.attr_name]
except AttributeError:
return getattr(instance, self.attr_name)

def __set__(self, instance, value):
try:
instance.__dict__[self.attr_name] = value
except AttributeError:
setattr(instance, self.attr_name, value)

(如果同时存在 __slots____dict__,则不会正常工作。)

但最近我发现了一种使用包装器劫持 __get____set__ 方法的方法:

def slot_wrapper(cls, slotname, slot, descriptor):
'''Wrapper replacing a slot descriptor with another one'''

class InnerDescr(descriptor):

def __get__(self, obj, cls):
print("Hijacking __get__ method of a member-descriptor")
return slot.__get__(obj, cls)

def __set__(self, obj, val):
print("Hijacking __set__ method of a member-descriptor")
slot.__set__(obj, val)

return InnerDescr(slotname, cls)

(用例是添加类型检查和数据验证,以及强制封装。)

因此,在创建类之后(或在使用元类之前),您可以为插槽和描述符保留相同的名称。

工作得很好,但感觉有点脏……我认为实现我自己的槽以继续为描述符使用同一个名称可能会更好。但我不知道怎么办。

所以这里有一些问题:

  1. 实际存储的值在哪里(因为没有字典)?我在想它是用 C 实现的,不能直接用 Python 代码访问。

  2. 如何在不损失性能优化的情况下实现纯 Python 等价物?

  3. 坚持使用我的 wrapper 更好吗?

最佳答案

Where are actually storerd the values (since there is no dict) ? I was thinking it's something implemented in C and not directly accessible with Python code.

直接在对象本身中为 PyObject * 指针分配内存。您可以在 Objects/typeobject.c 中看到处理.生成的描述符将访问为其在适当类型的对象中的插槽保留的内存。

How can I implement a pure python equivalent without losing performance optimization?

你不能。您可以获得的最接近的是扩展 tuple

It is prefarable to stick with my wrapper?

没有。不要将您的插槽命名为与您希望由其他描述符处理的属性相同的名称。这样做就像命名两个非插槽描述符一样;对于如何处理具有该名称的属性,您表达了两个相互矛盾的意图。

关于python - __slots__ 是如何工作的,你如何实现自己的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46028830/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com