使用带槽的 Python 描述符
我希望能够在具有插槽优化的类中使用 python 描述符:
class C(object):
__slots__ = ['a']
a = MyDescriptor('a')
def __init__(self, val):
self.a = val
我遇到的问题是如何实现描述符类以便能够在调用描述符对象的类实例中存储值。通常的解决方案如下所示,但不起作用,因为在 C 类中调用“slots”时不再定义“dict”:
class MyDescriptor(object):
__slots__ = ['name']
def __init__(self, name_):
self.name = name_
def __get__(self, instance, owner):
if self.name not in instance.__dict__:
raise AttributeError, self.name
return instance.__dict__[self.name]
def __set__(self, instance, value):
instance.__dict__[self.name] = value
I want to be able use python descriptors in a class which has the slots optimization:
class C(object):
__slots__ = ['a']
a = MyDescriptor('a')
def __init__(self, val):
self.a = val
The problem I have is how to implement the descriptor class in order to be able to store values in the class instance which invokes the descriptor object. The usual solution would look like the one below but will not work since "dict" is no longer defined when "slots" is invoked in the C class:
class MyDescriptor(object):
__slots__ = ['name']
def __init__(self, name_):
self.name = name_
def __get__(self, instance, owner):
if self.name not in instance.__dict__:
raise AttributeError, self.name
return instance.__dict__[self.name]
def __set__(self, instance, value):
instance.__dict__[self.name] = value
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不要将插槽和实例方法声明为相同的名称。使用不同的名称,并将插槽作为属性访问,而不是通过 __dict__ 。
Don't declare the same name as a slot and as an instance method. Use different names, and access the slot as an attribute, not via
__dict__
.尽管价值可疑,但如果可以将第一个 __slots__ 放入子类中,则以下技巧将起作用。
(您可以使用自己的描述符而不是属性。)使用这些定义:
据我了解,
__slots__
是用自己的描述符实现的,因此在__slots__
之后的另一个描述符同一个类只会覆盖。如果您想详细说明此技术,您可以在 self.__class__.__mro__ 中搜索候选描述符(或者在您自己的 __get__ 中从instance
开始) >)。后记
好吧...好吧,如果您确实想使用一个类,您可以使用以下改编:
如果您坚持难以理解,您可以在元类或类装饰器中进行分配。
Though of dubious value, the following trick will work, if it is ok to put the first
__slots__
in a subclass.(You can use your own descriptor rather than property.) With these definitions:
As far as I understand,
__slots__
is implemented with its own descriptor, so another descriptor after__slots__
in the same class would just overwrite. If you want to elaborate this technique, you could search for a candidate descriptor inself.__class__.__mro__
(or starting withinstance
in your own__get__
).Postscript
Ok ... well if you really want to use one class, you can use the following adaptation:
If you insist on inscrutability, you can make the assignment in a metaclass or a class decorator.
@Glenn Maynard 的答案很好。
但我想指出OP问题中的一个问题(我无法对他的问题添加评论,因为我还没有足够的声誉):
当实例没有
__dict__
变量:因此,这是一个通用解决方案,它首先尝试访问
__dict__
变量(无论如何都是默认值),如果失败,请使用getattr
和setattr
:(仅当
attr_name
与真实实例变量的名称不同时才有效,否则将出现RecursionError
正如已接受的答案中所指出的那样)(如果同时存在 __slots__ 和 __dict__ ,则不会按预期工作)
希望这会有所帮助。
The @Glenn Maynard's answer is the good one.
But I would like to point at a problem in the OP's question (I can't add a comment to his question since I havn't enough reputation yet):
The following test is raising an error when the instance hasn't a
__dict__
variable:So, here is an a generic solution that tries to acces to the
__dict__
variable first (which is the default anyway) and, if it fails, usegetattr
andsetattr
:(Works only if the
attr_name
is not the same as the real instance variable's name, or you will have aRecursionError
as pointed to in the accepted answer)(Won't work as expected if there is both
__slots__
AND__dict__
)Hope this helps.