【发布时间】:2020-12-03 05:04:09
【问题描述】:
在元类中实现数据描述符的正确方法是什么?在下面的(简单的)示例中,我希望始终在设置所需的值之前附加一个问号:
class AddQDesc:
def __init__ (self, name):
self.name = name
def __get__ (self, instance, owner=None):
obj = instance if instance != None else owner
return obj.__dict__[self.name]
def __set__ (self, instance, value):
# What should go here ?
#setattr(instance, self.name, "{}?".format(value)) <- This gives me recursion error
#instance.__dict__[self.name] = "{}?".format(value) <- This gives me proxymapping error
pass
class Meta (type):
var = AddQDesc("var")
class C (metaclass=Meta):
var = 5
print(C.var)
C.var = 1
print(C.var)
首先,当我将 var 初始化为 5 时,似乎没有使用描述符。我可以在此处也以某种方式应用描述符协议吗? (设为“5?”) 二、在 __set__ 方法中应该如何更新值?更新 __dict__ 给我 "TypeError: 'mappingproxy' 对象不支持项目分配" 并且使用 setattr 给我 "RecursionError: 超出最大递归深度同时调用 Python 对象”。
【问题讨论】:
-
我无法正确回答您的问题,但您可以查看 Python 文档中的 property 类或 Descriptor howto guide。不过我可以说的是,在
python class C (metaclass=Meta): var = 5中,您将元类中的属性“var”替换为完全不同的属性,这是正常的:继承是关于覆盖父类的行为。 -
是的 - 这很棘手 - 我在轨道上,但现在没有时间。如果您不需要将属性实际存储在具有相同名称的 class.__dict__ 中,这将更容易 - 这对于普通对象来说很容易。但是,如果名称可以是一个错位的名称(如“_var”),或者如果数据存储可以在描述符实例中,而不是在类中,那就很简单了。
-
然而,能够在类主体中指定一个初始值可能是一个有趣的问题。我不知道 itf type.__new__,它将设置这些初始属性,将使用描述符协议 - 稍后会检查。
-
(事实证明,
type.__new__忽略元类中的描述符以分配初始类属性 - 我的答案包括解决方法)
标签: python-3.x metaclass python-descriptors