Are decorators really that different from metaclasses...

Andrew Durdin adurdin at gmail.com
Fri Aug 27 03:32:12 CEST 2004


On Thu, 26 Aug 2004 20:54:22 -0400, Paul Morrow <pm_mon at yahoo.com> wrote:
>
> Sure the interpreter uses __getitem__, but you use it too, right?  I
> mean, you don't need the interpreter to tell you whether instances of
> the following class can act like a dictionary, do you?
> 
>     class Foo:
>        def __getitem__(self, x): pass
> 
> No you don't.  Nor do you need to pretend that you're the interpreter,
> and simulate a call to an instance of Foo.  That's because the mere
> presence of def __getitem__ tells you what you need to know.  In this
> way, __getitem__ *does* serve as a declaration (of dictionary semantics)
> [*] to you and anyone reading your code.

That's because the dictionary interface/protocol requires a
__getitem__ method; there's no magical/technical reason why it should
be called __getitem__ rather than, say,  dict_get_item.
As an example, the iterator protocol requires two methods: __iter__()
and next() -- the second doesn't have the double underscores, yet
still allows you to do:

class Foo:
    def __iter__(self):
        return self
    def next(self):
        return 42

for v in Foo():
    print v

(yes, that's an infinite loop, but that's irrelevant). All the "magic"
__X__ methods are just those methods required by certain built-in
interfaces/protocols. And there's syntactic sugar to make them
convenient. They don't affect the creation of the class at all, as you
can (if necessary) add them in after the fact:

>>> class Foo:
...     pass
...
>>> for i in Foo():
...     pass
...
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: iteration over non-sequence
>>> def bar(self):
...     return self
...
>>> def baz(self):
...     raise StopIteration()
...
>>> Foo.__iter__ = bar
>>> Foo.next = baz
>>> for i in Foo():
...     pass
...
>>>



More information about the Python-list mailing list