简体   繁体   English

将类描述符与get和set一起使用时,超过了最大递归深度

[英]maximum recursion depth exceeded when using a class descriptor with get and set

I have been playing with my code and I ended up with this: 我一直在玩我的代码,最终得到了以下结果:

class TestProperty:
    def __init__(self,func):
         self.func = func
    def __set__(self,instance,value):
        setattr(instance,self.func.__name__,value)
    def __get__(self,instance,cls):
        if instance is None:
            return self
        else:
            return getattr(instance,self.func.__name__)


class John(object):
    def __init__(self):
        pass

    @TestProperty
    def TestProp(self):
       print('This line won\'t be printed')

p = John()
p.TestProp = 99
print(p.TestProp)

I'm trying to understand the behavior when creating a class descriptor and using them on methods instead of attributes. 我试图了解在创建类描述符并将其用于方法而不是属性时的行为。 I am having a hard time understanding what's going on underneath and It would be really nice if someone can shed some light on me how did this end up as recursive error? 我很难理解下面发生了什么,如果有人可以向我阐明一下这真是太好了,这怎么会成为递归错误?

My initial guess is something like this: 我最初的猜测是这样的:

  1. Method that is decorated with the descriptor is called 用描述符修饰的方法称为
  2. Calls either __set__ or __get__ depending on how we accessed it. 根据我们访问它的方式调用__set____get__
  3. Descriptors attempts to set the value of the instance which calls which ends up mapping it back to step 1(error). 描述符尝试设置调用实例的值,该实例最终将其映射回步骤1(错误)。

Can anyone explain to me in great detail how did this happen and how do I resolve this? 谁能向我详细解释这是怎么发生的以及我该如何解决?

The code provided serves no purpose other than understanding the behavior of class descriptor. 提供的代码除了了解类描述符的行为外没有其他用途。

Don't use getattr() and setattr() ; 不要使用getattr()setattr() ; you are triggering the descriptor again there! 您正在那里再次触发描述符! The descriptor handles all access to the TestProp name, using setattr() and getattr() just goes through the same path as p.TestProp would. 描述符使用setattr()getattr()处理所有对TestProp名称的访问,就像通过p.TestProp一样。

Set the attribute value directly in the instance.__dict__ : 直接在instance.__dict__设置属性值。

def __get__(self,instance,cls):
    if instance is None:
        return self
    try:
        return instance.__dict__[self.func.__name__]
    except KeyError:
        raise AttributeError(self.func.__name__)
def __set__(self,instance,value):
    instance.__dict__[self.func.__name__] = value

This works because you have a data descriptor ; 之所以有效,是因为您有一个数据描述符 ; a data descriptor takes precedence over instance attributes. 数据描述符优先于实例属性。 Access to p.TestProp continues to use the descriptor object on the class even though the name 'TestProp' exists in instance __dict__ . 即使实例__dict__存在名称'TestProp'p.TestProp访问p.TestProp继续使用该类上的描述符对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM