简体   繁体   中英

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.
  3. Descriptors attempts to set the value of the instance which calls which ends up mapping it back to step 1(error).

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() ; 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.

Set the attribute value directly in the 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__ .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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