delegation pattern via descriptor

K

kedra marbun

kedra marbun a écrit :






Nothing prevents you to pass a "name" to the descriptor instance when
instanciating it, ie:

class Desc(object):
     def __init__(self, name):
         self.name = name
    def __get__(self, inst, cls):
        # ...
    def __set__(self, inst, value):
        # ...

class Foo(object):
     bar = Desc("bar")
     baaz = Desc("baaz")

Ok, this is not necessarily what you were looking for, but it's IMHO
less brittle than relying on which attribute name was looked up (which
is something the descriptor shouldn't have to care about).




In Python 2.x, not that I know (but it may have passed under my radar).
If what you want it to automate delegation of a set of methods without
too much manual coding, you can use a custom metaclass that will add the
relevant methods to the class, based on (ie) a list (or mapping) of
methods names. But that might be a bit overkill.



I don't see the point of using delegation on a class attribute. That's
typically what inheritance is for.

ah, our friend mixin, it's just a sample though
Err... Did you try the simple way ?
                         return getattr(self.a, name)

argh, that should be
class A:
def do_this(self, ins): ...
 
K

kedra marbun

The same answer applies. It's assumed that you will be
writing a custom piece of code for each attribute of
each class, and giving each one its own descriptor.

By the time you get to the get or set method of a
descriptor, you've already dispatched on both the
class and attribute name. There is not usually any
point in funnelling things back into a single function
and then dispatching on the class or name again.
Passing the class or name would just add overhead that
was unnecessary in the majority of use cases.

True, unnecessary overhead. this 'passing class' thing comes from,
IIRC, learning python 4ed by Mark Lutz, it's stated there that the 3rd
arg to __get__ is the class to which the descriptor instance is
attached

so if i want the host class, i should do it the way builtin
descriptors do (bind it manually)? for example,
type.__dict__['__getattribute__'].__class__ is wrapper_descriptor.
wrapper_descriptor has member __objclass__ pointing to instance of
types.MemberDescriptorType, which disallows set & del, get returns the
host class ('type' in this case)

***
about the 3rd arg of __get__
i guess py has chosen __get__(self, ins, cls) over __get__(self, ins)
to make it easier for decriptor-implementor to find out whether the
caller (the left-side operand of dot operator) is instance of obj on
which the descriptor obj is found or not

this conclusion is based on the fact that:
- it is only __get__ that receives the redundant class obj
- if the caller is a class obj & descriptor is found on obj that is in
its __mro__, the fetch is still routed to __get__: __get__(desc, None,
CLASS). this doesn't happen for __{set|delete}__

note that the builtin descriptors even allow their's __get__ to be
given only the instance (2nd arg):
object.__getattribute__.__get__(obj)

is it correct?
 
G

Gregory Ewing

kedra said:
this 'passing class' thing comes from,
IIRC, learning python 4ed by Mark Lutz, it's stated there that the 3rd
arg to __get__ is the class to which the descriptor instance is
attached

That's there so that the __get__ method of function
objects can return an unbound method when looked up
on a class rather than an instance of the class.

There is no corresponding use case for a class argument
to __set__ or __delete__, so they don't have one.
 

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,278
Latest member
BuzzDefenderpro

Latest Threads

Top