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