Re: code explanation

Discussion in 'Python' started by Steven D'Aprano, Jan 15, 2013.

  1. On Mon, 14 Jan 2013 23:00:16 -0500, Rodrick Brown wrote:

    > Can someone explain what's going on here.
    >
    > def _build_magic_dispatcher(method):
    > def inner(self, *args, **kwargs):
    > return self.__dict__[method](*args, **kwargs)
    > inner.__name__ = method
    > return inner
    >
    > Thanks.



    This is a factory function, probably intended to be used as a decorator:

    class K:
    @_build_magic_dispatcher
    def something(self, x, y, z): ...

    except that it appears to be broken. It seems to be expecting a *string*,
    the name of a method, despite the function parameter claiming to require
    a method itself. So maybe you use it like this:

    class K:
    def __init__(self):
    self.parrot = _build_magic_dispatcher("parrot")


    or something similar. Without seeing the context, it's hard for me to
    tell whether it works or is broken. I suspect it is broken, or useless,
    or both.

    So, this factory function seems to take the *name* of a method as
    argument. Then it builds an inner method, which accepts arbitrary
    arguments (args and kwargs), renames the inner method to the name you
    passed as argument, and returns it.

    The inner method simply looks up an attribute with the same name, and
    calls it as a function with whatever args and kwargs it gets.


    Does this help?



    --
    Steven
    Steven D'Aprano, Jan 15, 2013
    #1
    1. Advertising

  2. On Mon, Jan 14, 2013 at 11:38 PM, Steven D'Aprano <
    > wrote:

    > On Mon, 14 Jan 2013 23:00:16 -0500, Rodrick Brown wrote:
    >
    > > Can someone explain what's going on here.
    > >
    > > def _build_magic_dispatcher(method):
    > > def inner(self, *args, **kwargs):
    > > return self.__dict__[method](*args, **kwargs)
    > > inner.__name__ = method
    > > return inner
    > >
    > > Thanks.

    >
    >
    > This is a factory function, probably intended to be used as a decorator:
    >
    > class K:
    > @_build_magic_dispatcher
    > def something(self, x, y, z): ...
    >
    > except that it appears to be broken. It seems to be expecting a *string*,
    > the name of a method, despite the function parameter claiming to require
    > a method itself. So maybe you use it like this:
    >
    > class K:
    > def __init__(self):
    > self.parrot = _build_magic_dispatcher("parrot")
    >
    >
    > or something similar. Without seeing the context, it's hard for me to
    > tell whether it works or is broken. I suspect it is broken, or useless,
    > or both.
    >
    > So, this factory function seems to take the *name* of a method as
    > argument. Then it builds an inner method, which accepts arbitrary
    > arguments (args and kwargs), renames the inner method to the name you
    > passed as argument, and returns it.
    >
    >

    Thanks Steven, here is the full context of the code. I'm trying to
    understand what exactly the author is trying to accomplish here.

    import sys

    PY3K = sys.version_info >= (3,)


    methods = set([
    "__iter__",
    "__len__",
    "__contains__",

    "__lt__",
    "__le__",
    "__eq__",
    "__ne__",
    "__gt__",
    "__ge__",

    "__add__",
    "__and__",
    "__divmod__",
    "__floordiv__",
    "__lshift__",
    "__mod__",
    "__mul__",
    "__or__",
    "__pow__",
    "__rshift__",
    "__sub__",
    "__truediv__",
    "__xor__",
    ])
    if PY3K:
    methods.add("__next__")
    methods.add("__bool__")
    else:
    methods.add("__div__")
    methods.add("__nonzero__")
    MAGIC_METHODS = frozenset(methods)
    del methods

    def _build_magic_dispatcher(method):
    def inner(self, *args, **kwargs):
    return self.__dict__[method](*args, **kwargs)
    inner.__name__ = method
    return inner


    class stub(object):
    _classes_cache = {}

    def __new__(cls, **kwargs):
    magic_methods_present = MAGIC_METHODS.intersection(kwargs)
    if magic_methods_present not in cls._classes_cache:
    attrs = dict(
    (method, _build_magic_dispatcher(method))
    for method in magic_methods_present
    )
    attrs["__module__"] = cls.__module__
    cls._classes_cache[magic_methods_present] = type("stub",
    (cls,), attrs)
    new_cls = cls._classes_cache[magic_methods_present]
    return super(stub, new_cls).__new__(new_cls, **kwargs)

    def __init__(self, **kwargs):
    self.__dict__.update(kwargs)


    > The inner method simply looks up an attribute with the same name, and
    > calls it as a function with whatever args and kwargs it gets.
    >
    >
    > Does this help?
    >
    >
    >
    > --
    > Steven
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >
    Rodrick Brown, Jan 15, 2013
    #2
    1. Advertising

  3. Steven D'Aprano

    Ian Kelly Guest

    On Mon, Jan 14, 2013 at 9:51 PM, Rodrick Brown <> wrote:
    > import sys
    >
    > PY3K = sys.version_info >= (3,)
    >
    >
    > methods = set([
    > "__iter__",
    > "__len__",
    > "__contains__",
    >
    > "__lt__",
    > "__le__",
    > "__eq__",
    > "__ne__",
    > "__gt__",
    > "__ge__",
    >
    > "__add__",
    > "__and__",
    > "__divmod__",
    > "__floordiv__",
    > "__lshift__",
    > "__mod__",
    > "__mul__",
    > "__or__",
    > "__pow__",
    > "__rshift__",
    > "__sub__",
    > "__truediv__",
    > "__xor__",
    > ])
    > if PY3K:
    > methods.add("__next__")
    > methods.add("__bool__")
    > else:
    > methods.add("__div__")
    > methods.add("__nonzero__")
    > MAGIC_METHODS = frozenset(methods)
    > del methods
    >
    > def _build_magic_dispatcher(method):
    > def inner(self, *args, **kwargs):
    > return self.__dict__[method](*args, **kwargs)
    > inner.__name__ = method
    > return inner
    >
    >
    > class stub(object):
    > _classes_cache = {}
    >
    > def __new__(cls, **kwargs):
    > magic_methods_present = MAGIC_METHODS.intersection(kwargs)
    > if magic_methods_present not in cls._classes_cache:
    > attrs = dict(
    > (method, _build_magic_dispatcher(method))
    > for method in magic_methods_present
    > )
    > attrs["__module__"] = cls.__module__
    > cls._classes_cache[magic_methods_present] = type("stub", (cls,),
    > attrs)
    > new_cls = cls._classes_cache[magic_methods_present]
    > return super(stub, new_cls).__new__(new_cls, **kwargs)
    >
    > def __init__(self, **kwargs):
    > self.__dict__.update(kwargs)



    The stub class is called with keyword arguments where the keys are the
    names of Python "magic methods" and the values are functions. When
    called, it builds a new subclass of itself populated with a
    corresponding set of methods, each of which is built by
    _build_magic_dispatcher; these look up the method with the same name
    in the instance dictionary and delegate the call to whatever they
    find. For some reason that eludes me, the generated methods appear to
    discard the "self" argument in the process. After the subclass is
    generated, it constructs and returns an instance of the subclass, and
    then when the __init__ method is called it simply populates the
    instance dictionary with the functions that were passed in.

    The purpose of this appears to be to construct objects with magic
    methods that are defined on the object itself rather than on the
    class. Normally, when Python calls a magic method it doesn't look in
    the instance dictionary at all and only looks in the class dictionary.
    The subclasses of "stub" side-step that by having the desired magic
    methods on the class delegate calls to the instance.
    Ian Kelly, Jan 15, 2013
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. uthra
    Replies:
    1
    Views:
    398
    John Gordon
    Nov 10, 2006
  2. responsible
    Replies:
    4
    Views:
    329
    red floyd
    Aug 5, 2008
  3. Neville Franks

    Code explanation requeted

    Neville Franks, Feb 5, 2007, in forum: Ruby
    Replies:
    4
    Views:
    102
    Marcello Barnaba
    Feb 6, 2007
  4. Michael Albers

    Explanation on some code

    Michael Albers, Dec 1, 2008, in forum: Ruby
    Replies:
    5
    Views:
    111
    Robert Dober
    Dec 1, 2008
  5. Phil Thompson

    Explanation of code needed

    Phil Thompson, Mar 21, 2005, in forum: Javascript
    Replies:
    4
    Views:
    151
    Phil Thompson
    Mar 22, 2005
Loading...

Share This Page