[Python-ideas] Restore the __members__ behavior to python3 for C extension writers

Nick Coghlan ncoghlan at gmail.com
Mon Jun 19 08:56:32 EDT 2017


On 19 June 2017 at 04:10, Barry Scott <barry at barrys-emacs.org> wrote:
> The code does this:
>
>     Py::Object getattro( const Py::String &name_ )
>     {
>         std::string name( name_.as_std_string( "utf-8" ) );
>
>         if( name == "value" )
>         {
>             return m_value;
>         }
>         else
>         {
>             return genericGetAttro( name_ );
>         }
>     }
>
> Where getattro is called (indirectly) from tp_getattro.
>
> In the python 2 I can tell python that 'value' exists because I provide a value of __members__.
>
> What is the way to tell python about 'value' in the python3 world?

OK, I think I may understand the confusion now.

As Thomas noted, the preferred way of informing Python of data
attributes for types implemented in C is to ask the interpreter to
automatically create the appropriate descriptor objects by setting the
`tp_members` slot on the C level *type*, rather than setting
`__members__` on the instance:
https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_members

That approach also works for new-style classes in Python 2:
https://docs.python.org/2/c-api/typeobj.html#c.PyTypeObject.tp_members

I believe this is actually an old-/new-style class difference, so the
relevant Python 3 change is the fact that the old-style approach
simply isn't available any more.

So if you use tp_members and tp_getset to request the creation of
suitable descriptors, then the interpreter will automatically take
care of populating the results of `dir()` correctly. However, if
you're genuinely dynamically adding attributes in `__getattr__`, then
you're going to need to add code to report them from `__dir__` as
well.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list