Getting not derived members of a class

Jeff Epler jepler at unpythonic.net
Mon Aug 1 11:24:53 EDT 2005


On 'y', Python has no way of recording where '_a' and '_b' were set, so
you can't tell whether it comes from class 'a' or 'b'.

You can find the attributes that are defined on 'b' only, though, by
using 'b.__dict__.keys()', or 'y.__class__.__dict__.__keys__()'.  This
gives
    ['__module__', 'who1', '__init__', '__doc__']

If you want to limit yourself to current versions of cpython (because the
bytecode used in cpython is only an implementation detail) and define a 'member
of class a' as one where a.__init__ has a statement like 'self.z = ...', you
can peer into the bytecodes.  Something like this:
    from dis import HAVE_ARGUMENT, opname
    LOAD_FAST = chr(opname.index('LOAD_FAST'))
    STORE_ATTR = chr(opname.index('STORE_ATTR'))
    HAVE_ARGUMENT = chr(HAVE_ARGUMENT)

    def find(cls):
        ns = cls.__dict__
        result = ns.keys()
        init = ns.get('__init__', None)
        if not init: return ns
        f = ns['__init__'].func_code.co_code
        n = ns['__init__'].func_code.co_names
        i = 0
        while i < len(f) - 6:
            if (f[i] == LOAD_FAST and f[i+1] == f[i+2] == '\0'
                    and f[i+3] == STORE_ATTR):
                j = ord(f[i+4]) + 256 * ord(f[i+5])
                result.append(n[j])
                i += 6
            elif f[i] > HAVE_ARGUMENT:
                i += 3
            else:
                i += 1
        return result

>>> import franz
>>> franz.find(y.__class__)
['__module__', 'who1', '__init__', '__doc__', '_b']

Jeff
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/python-list/attachments/20050801/044efc77/attachment.sig>


More information about the Python-list mailing list