Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #36836

Re: code explanation

Path csiph.com!newsfeed.hal-mli.net!feeder3.hal-mli.net!newsfeed.hal-mli.net!feeder1.hal-mli.net!newsfeed.xs4all.nl!newsfeed3.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail
Return-Path <ian.g.kelly@gmail.com>
X-Original-To python-list@python.org
Delivered-To python-list@mail.python.org
X-Spam-Status OK 0.000
X-Spam-Evidence '*H*': 1.00; '*S*': 0.00; 'else:': 0.03; 'argument': 0.04; 'discard': 0.05; 'sys': 0.05; '*args,': 0.07; 'arguments': 0.07; 'subject:code': 0.07; 'python': 0.09; '**kwargs)': 0.09; '**kwargs):': 0.09; '__init__': 0.09; 'instance.': 0.09; 'methods,': 0.09; 'normally,': 0.09; 'subclass': 0.09; 'subclasses': 0.09; 'def': 0.10; 'attrs': 0.16; 'called,': 0.16; 'constructs': 0.16; 'dict(': 0.16; 'dictionary.': 0.16; 'generated,': 0.16; 'stub': 0.16; 'mon,': 0.16; 'wrote:': 0.17; 'instance': 0.17; 'jan': 0.18; 'appears': 0.18; 'import': 0.21; 'keys': 0.22; 'defined': 0.22; 'skip:_ 20': 0.22; 'class.': 0.23; 'header:In-Reply-To:1': 0.25; 'appear': 0.26; 'looks': 0.26; 'values': 0.26; 'skip:m 30': 0.26; 'functions.': 0.27; 'in.': 0.27; 'message-id:@mail.gmail.com': 0.27; "doesn't": 0.28; 'dictionary': 0.29; 'objects': 0.29; 'skip:_ 10': 0.29; 'class': 0.29; 'keyword': 0.30; 'skip:_ 30': 0.32; 'builds': 0.33; 'to:addr :python-list': 0.33; 'received:google.com': 0.34; 'whatever': 0.35; 'pm,': 0.35; 'received:209.85.220': 0.35; 'received:209.85': 0.35; 'method': 0.36; 'itself': 0.37; 'passed': 0.37; 'rather': 0.37; 'received:209': 0.37; 'subject:: ': 0.38; 'object': 0.38; 'some': 0.38; 'to:addr:python.org': 0.39; 'called': 0.39; 'where': 0.40; 'skip:" 10': 0.40; 'header:Received:5': 0.40; 'brown': 0.65; 'delegate': 0.65; '2013': 0.84; 'construct': 0.84; 'find.': 0.84; 'to:name:python': 0.84
DKIM-Signature v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :content-type; bh=8QIucdXtS30RFrAw9tZsEfxN1YBV1Sa9qXB6wqaiprM=; b=s13G6wkZ+g02vq2VQS//5v+dc5/2f2xp8J1KWWpLcfh9NK4NBy/kaiDXqXbr5kG24d kq+/fHdd7lb3No1AagNS341DK89ZdFw9QNRrsQQVABii4ob2Wy82oH8Dxhq7TqftblzV u8kQ/Mq40tke4ATAEK31TPVdQ7PB6tPE6QGx85w5MwWBD4RHlPp5Sv0PS6N4m6ANqKK6 AdG2q3g6CoU8BWx7hwoilpr1k0Grmh8E/4rdP06QqJH0g9J6ph7QAKM8UmMUuJZPHDqe 5e2QgImtNZLUG+Sdl3aNh1eBAdOD6HVckN4qPBrteVvy0hTDe8/l1NeVT7qIACcGw/iD k06w==
MIME-Version 1.0
In-Reply-To <CABRP1o_YAUbXg_Y9UvJr1bgKZT89kiNSqF2xopnrHYNqyK79iA@mail.gmail.com>
References <mailman.526.1358222451.2939.python-list@python.org> <50f4dd31$0$29983$c3e8da3$5496439d@news.astraweb.com> <CABRP1o_YAUbXg_Y9UvJr1bgKZT89kiNSqF2xopnrHYNqyK79iA@mail.gmail.com>
From Ian Kelly <ian.g.kelly@gmail.com>
Date Mon, 14 Jan 2013 22:39:57 -0700
Subject Re: code explanation
To Python <python-list@python.org>
Content-Type text/plain; charset=ISO-8859-1
X-BeenThere python-list@python.org
X-Mailman-Version 2.1.15
Precedence list
List-Id General discussion list for the Python programming language <python-list.python.org>
List-Unsubscribe <http://mail.python.org/mailman/options/python-list>, <mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive <http://mail.python.org/pipermail/python-list/>
List-Post <mailto:python-list@python.org>
List-Help <mailto:python-list-request@python.org?subject=help>
List-Subscribe <http://mail.python.org/mailman/listinfo/python-list>, <mailto:python-list-request@python.org?subject=subscribe>
Newsgroups comp.lang.python
Message-ID <mailman.529.1358228435.2939.python-list@python.org> (permalink)
Lines 86
NNTP-Posting-Host 2001:888:2000:d::a6
X-Trace 1358228435 news.xs4all.nl 6911 [2001:888:2000:d::a6]:52651
X-Complaints-To abuse@xs4all.nl
Xref csiph.com comp.lang.python:36836

Show key headers only | View raw


On Mon, Jan 14, 2013 at 9:51 PM, Rodrick Brown <rodrick.brown@gmail.com> 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.

Back to comp.lang.python | Previous | NextPrevious in thread | Find similar | Unroll thread


Thread

code explanation Rodrick Brown <rodrick.brown@gmail.com> - 2013-01-14 23:00 -0500
  Re: code explanation Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-01-15 04:38 +0000
    Re: code explanation Rodrick Brown <rodrick.brown@gmail.com> - 2013-01-14 23:51 -0500
    Re: code explanation Ian Kelly <ian.g.kelly@gmail.com> - 2013-01-14 22:39 -0700

csiph-web