python3在元类中实现数据描述符

问题描述

元类内部实现数据描述符的正确方法是什么?在下面的示例中,我希望始终在设置所需值之前附加一个问号:

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,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代码无法直接更改类的__dict__属性-必须调用setattr并让Python设置类属性-并且setattr将“看到”元类中的描述符,并调用其__set__而不是修改类__dict__本身的值。因此,您将获得无限递归循环。

因此,如果您真的要求由描述符代理的属性将在类的“ dict”中以相同的名称“生效”,则您必须采取以下措施:设置值时,暂时删除来自元类的描述符,调用setattr来设置值,然后将其还原。

此外,如果要处理在类主体中设置的值, 通过描述符,必须在{ 类已创建-setattr将不检查描述符 在构建初始类type.__new__时。

__dict__

如果您不需要将值保留在类的from threading import Lock class AddQDesc: def __init__ (self,name): self.name = name self.lock = Lock() def __get__ (self,instance,owner=None): obj = instance if instance != None else owner return obj.__dict__[self.name] def __set__ (self,value): owner_metaclass = type(instance) with self.lock: # Temporarily remove the descriptor to avoid recursion problems try: # Note that a metaclass-inheritance hierarchy,where # the descriptor might be placed in a superclass # of the instance's metaclass,is not handled here. delattr(owner_metaclass,self.name) setattr(instance,self.name,value + 1) finally: setattr(owner_metaclass,self) class Meta (type): def __new__(mcls,name,bases,namespace): post_init = {} for key,value in list(namespace.items()): if isinstance(getattr(mcls,key,None),AddQDesc): post_init[key] = value del namespace[key] cls = super().__new__(mcls,namespace) for key,value in post_init.items(): setattr(cls,value) return cls var = AddQDesc("var") class C (metaclass=Meta): var = 5 print(C.var) C.var = 1 print(C.var) 中,建议将其存储在其他位置-例如,在描述符实例中以类为键的字典就足够了-而且会变得更不可思议。

__dict__

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...