Descriptors as instance attributes in python

后端 未结 3 781
挽巷
挽巷 2020-12-05 02:56

To the question:

Why can\'t descriptors be instance attributes?

it has been answered that:

descriptor obj

3条回答
  •  抹茶落季
    2020-12-05 03:32

    Plenty of advanced functionality only works when defined on a class rather than an instance; all of the special methods, for example. As well as making code evaluation more efficient, this makes clear the separation between instances and types which otherwise would tend to collapse (because of course all types are objects).

    I'm not sure how recommended this is, but you could in the instance store a mapping from descriptor instance to attribute value:

    class Prop(object):
         def __get__(self, obj, objtype=None):
            if obj is None:
                return self
            return obj._value * obj._multiplier[self]
    
        def __set__(self, obj, value):
            if obj is None:
                return self
            obj._value = value
    
    class Obj(object):
        val = Prop()
    
        def __init__(self):
            self._value = 1
            self._multiplier = {Obj.val: 0}
    

    This has obvious advantages over the other two suggested options:

    1. per-instance classes break object orientation and increase memory usage;
    2. overriding __getattribute__ is inefficient (as all attribute access must go through the overridden special method) and is fragile.

    As an alternative, you could use a proxy property:

    class PerInstancePropertyProxy(object):
        def __init__(self, prop):
            self.prop = prop
        def __get__(self, instance, owner):
            if instance is None:
                return self
            return instance.__dict__[self.prop].__get__(instance, owner)
        def __set__(self, instance, value):
            instance.__dict__[self.prop].__set__(instance, value)
    class Prop(object):
        def __init__(self, value, multiplier):
            self.value = value
            self.multiplier = multiplier
        def __get__(self, instance, owner):
            if instance is None:
                return self
            return self.value * self.multiplier
        def __set__(self, instance, value):
            self.value = value
    class Obj(object):
        val = PerInstancePropertyProxy('val')
        def __init__(self):
            self.__dict__['val'] = Prop(1.0, 10.0)
        def prop(self, attr_name):
            return self.__dict__[attr_name]
    

提交回复
热议问题