Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
238 views
in Technique[技术] by (71.8m points)

python - Why is the Descriptor not getting called when defined as instance attribute?

When I make the "data" variable a class variable, the following works, but when I make it an object variable, the descriptor is not called. Please help.

class Data(object):
    products = {
        'milk': {'price': 1.50, 'quantity': 10},
        'eggs': {'price': 0.20, 'quantity': 100},
        'cheese': {'price': 2.00, 'quantity': 10}
    }
    def __get__(self, obj, klas):
        print "Here in descriptor"
        return self.products

class BusinessLogic(object):
    def __init__(self):         # When I remove these 2 lines 
        self.data = Data()
    #data = Data()             # and enable this line it does work !

def main():
    b = BusinessLogic()
    b.data

if __name__ == '__main__':
    main()
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

That's because descriptors should only be defined as class attributes, not instance attributes:

From docs:

The following methods only apply when an instance of the class containing the method (a so-called descriptor class) appears in an owner class (the descriptor must be in either the owner’s class dictionary or in the class dictionary for one of its parents).

To make descriptor work with instance attributes as well you need to override the __getattribute__ method of BusinessLogic.(Haven't tested this thoroughly, but works fine for your case):

def __getattribute__(self, attr):
        obj = object.__getattribute__(self, attr)
        if hasattr(obj, '__get__'):
            return obj.__get__(self, type(self))
        return obj

In case you've a data descriptor then you need to handle the __setattr__ part as well.

def __setattr__(self, attr, val):
    try:
        obj = object.__getattribute__(self, attr)
    except AttributeError:
        # This will be raised if we are setting the attribute for the first time
        # i.e inside `__init__` in your case.
        object.__setattr__(self, attr, val)
    else:
        if hasattr(obj, '__set__'):
            obj.__set__(self, val)
        else:
            object.__setattr__(self, attr, val)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...