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

Barry Scott barry at barrys-emacs.org
Sun Jun 18 14:10:52 EDT 2017

> On 16 Jun 2017, at 09:46, Nick Coghlan <ncoghlan at gmail.com> wrote:
> On 16 June 2017 at 07:44, Barry Scott <barry at barrys-emacs.org> wrote:
>> But I need the result of __dir__ for my object not its base. Then I need to
>> add in the list of member attributes that are missing because python
>> itself has no knowledge of them they are accessed via getattr().
> The C code:
>   dir_result = PyObject_CallMethod(base_type, "__dir__", "O", self);
> is roughly equivalent to the Python code:
>    dir_result = BaseType.__dir__(self)
> That is, it's calling the base type's __dir__ method, but it's still
> using the subclass *instance*.
> It's the same pattern people use to call a base type's __getattr__ or
> __getattribute__ for the subclass implementation of those methods,
> just without multiple inheritance support (since calling super() from
> C is painful).

Let me show you problem with an example.

Here is an example run of the PyCXX Demo/Python3/simple.cxx code.

:  19:01:15  ~/wc/svn/PyCXX
:  [1] barry at Expanse $ PYTHONPATH=obj python3.6
Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import simple
sizeof(int) 4
sizeof(long) 8
sizeof(Py_hash_t) 8
sizeof(Py_ssize_t) 8
>>> dir(simple)
['SimpleError', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'decode_test', 'derived_class_test', 'encode_test', 'func', 'func_with_callback', 'func_with_callback_catch_simple_error', 'make_instance', 'new_style_class', 'old_style_class', 'var']
>>> n=simple.new_style_class()
new_style_class c'tor Called with 0 normal arguments.
and with 0 keyword arguments:
>>> dir(n)
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_keyword', 'func_noargs', 'func_noargs_raise_exception', 'func_varargs', 'func_varargs_call_member']
>>> n.value
'default value'

Notice that 'value' is not in the list of string returned from dir(n).

That omission is because python does not know about 'value'.

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;
            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? 


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

More information about the Python-ideas mailing list