Search code examples
pythonpython-cffi

python cffi library object introspection results in __dict__ object change


I would like to get the full listing of enums from the header file using cffi. But I see a strange behaviour: by observing the object, I'm forcing the change in the underlying __dict__:

>>> from cffi import FFI
>>> ffi = FFI()
>>> ffi.cdef('typedef enum {RANDOM, IMMEDIATE, SEARCH} strategy;')
>>> c = ffi.dlopen('c')

# the dictionary is empty
>>> print c.__dict__
{}

>>> dir(c)

# the dictionary is populated
>>> print c.__dict__
{'SEARCH': 2, 'RANDOM': 0, 'IMMEDIATE': 1}

I'm guessing that __dict__ is not populated until first getattr() on the class is called, but the real question is: what does dir() do that populates __dict__? Calling hasattr() seems to do the same thing.


Solution

  • Technically, the reason for what you observe is that dir() tries to get a few special attributes like __members__ on the lib object. The code in cffi adds attributes lazily as they are computed. If a name is not found as a function, it proceeds to install all enums declarations and tries to return one of them if that's the name we try to read. That's why trying to read a non-existing name will always install all enums in lib.__dict__. (This logic is only for libs returned by ffi.dlopen(), not for the API mode.)

    Ideally, you should not rely on any of this, but in this case you have to: it is really a bug. Note that you can simply read dir(lib) twice: the second time, it will contain the enum values... (Fixed the bug in 19cae8d1a5f6: at least dir(lib) should always work in cffi 1.4---and no longer list all the special Python method names.)