Are decorators really that different from metaclasses...
Paul Morrow
pm_mon at yahoo.com
Sat Aug 28 08:45:20 EDT 2004
Bengt Richter wrote:
> On Fri, 27 Aug 2004 18:39:51 -0400, Paul Morrow <pm_mon at yahoo.com> wrote:
>
>
>>Anthony Baxter wrote:
>>
>>>On Thu, 26 Aug 2004 16:09:42 -0400, Paul Morrow <pm_mon at yahoo.com> wrote:
>>>
>>>
>>>>Yes, it doesn't seem all that complex, although I'm not sure that
>>>>everyone reading this understands them and their subtleties. The
>>>>following is an excerpt from
>>>>http://docs.python.org/tut/node11.html#SECTION0011200000000000000000
>>>>
>>>>"A namespace is a mapping from names to objects. Most namespaces are
>>>>currently implemented as Python dictionaries, but that's normally not
>>>>noticeable in any way (except for performance), and it may change in the
>>>>future. Examples of namespaces are: the set of built-in names (functions
>>>>such as abs(), and built-in exception names); the global names in a
>>>>module; and the local names in a function invocation. In a sense the set
>>>>of attributes of an object also form a namespace."
>>>
>>>
>>>>When I talk about namespaces, I include all of the above, including the
>>>>sense mentioned in the last line. So an object's attributes constitute
>>>>a namespace too. Therefore __doc__, being an attribute of the function
>>>>object, is in the function object's /namespace/. And note that this is
>>>>*not* a new namespace; it's been there all along.
>>>
>>>
>>>"In a sense" is the bit you're missing here. You can't just hand-wave
>>>and say that it's a namespace. It's *not* a namespace. If it was, you
>>>could do any of these:
>>>
>>
>>No I didn't miss it (I read that bit). In a sense, every object has
>>it's own namespace. So that means that every class, every module, every
>>function has a namespace (in a sense). The namespace (the mapping from
>>names to objects) is stored in each object's special __dict__ attribute.
>>
>>Ok, and this is certainly apparent with classes.
>>
>> >>> class Foo:
>> ... """docstring for Foo"""
>> ...
>> >>> Foo.__doc__
>> 'docstring for Foo'
>> >>> Foo.__dict__.keys()
>> ['__module__', '__doc__']
>> >>>
>>
>>And because of the parallels between the above class definition of Foo
>>and the following function definition of baz, I would expect the same
>>behavior.
>>
>> >>> def baz():
>> ... """docstring of baz"""
>> ...
>> >>> baz.__doc__
>> 'docstring of baz'
>> >>> baz.__dict__.keys()
>> []
>>
>>Say what? Why didn't the Python system put baz's docstring into it's
>>namespace (__dict__)? And where did it put it?
>>
>>I would like to understand the answers to these questions. Can you
>>answer them (will you)? If not, can you please point me at something
>>that documents what's going on here?
>>
>>Thanks.
>>
>
> It looks to me like __doc__ is a descriptor (or c-code that acts like one)
> (i.e., like a property) of the function class:
>
> >>> def foo():
> ... 'foo doc string'
> ...
>
> Find __doc__ in the class dict:
> >>> type(foo).__dict__['__doc__']
> <member '__doc__' of 'function' objects>
>
> Check on its nature a little:
> >>> type(type(foo).__dict__['__doc__'])
> <type 'member_descriptor'>
>
> It should have a __get__ method
> >>> type(foo).__dict__['__doc__'].__get__
> <method-wrapper object at 0x00901410>
>
> Call that with foo as object instance:
> >>> type(foo).__dict__['__doc__'].__get__(foo,None)
> 'foo doc string'
>
> Try writing the __doc__ property (check for __set__ first):
> >>> type(foo).__dict__['__doc__'].__set__
> <method-wrapper object at 0x00901490>
>
> Do long version of foo.__doc__ = 'new docstring'
> >>> type(foo).__dict__['__doc__'].__set__(foo, 'new docstring') # foo.__doc__ = ...
>
> Look at it using the short spelling:
> >>> foo.__doc__
> 'new docstring'
>
> And the long:
> >>> type(foo).__dict__['__doc__'].__get__(foo,None)
> 'new docstring'
>
> foo.func_doc seems to be implemented in a similar way:
> >>> type(foo).__dict__['func_doc'].__get__(foo,None)
> 'new docstring'
> >>> foo.func_doc
> 'new docstring'
>
> Even the dict of a function instance appears to be implemented as a property:
> >>> type(type(foo).__dict__['__dict__'])
> <type 'getset_descriptor'>
> >>> type(foo).__dict__['__dict__'].__get__(foo,None)
> {}
> >>> foo.x=123
> >>> type(foo).__dict__['__dict__'].__get__(foo,None)
> {'x': 123}
>
> Short spelling:
> >>> foo.__dict__
> {'x': 123}
>
> I haven't been into the implementation code, but this interpretation
> of surface appearances seems to fit.
>
> Regards,
> Bengt Richter
Cool! Thanks! Now I need to ponder why a function's docstring needs a
different implementation than a class's docstring (i.e. why not just
make it a straigtforward attribute of the function object).
More information about the Python-list
mailing list