inspect.getmembers in order?

后端 未结 6 1894
栀梦
栀梦 2021-01-01 10:54
inspect.getmembers(object[, predicate])

Return all the members of an object in a list of (name, value) pairs sorted by nam

相关标签:
6条回答
  • 2021-01-01 11:33

    I don't think Python 2.6 has a __prepare__ method, so I can't swap out the default dict for an ordered one. I can, however, replace it using a metaclass and the __new__ method. Instead of inspecting line numbers, I think its easier and more efficient to just use a creation counter.

    class MetaForm(type):
        def __new__(cls, name, bases, attrs):
            attrs['fields'] = OrderedDict(
                sorted(
                    [(name, attrs.pop(name)) for name, field in attrs.items() if isinstance(field, Field)],
                    key=lambda t: t[1].counter
                )
            )
            return type.__new__(cls, name, bases, attrs)
    
    class Form(object):
        __metaclass__ = MetaForm
    
    class Field(object):
        counter = 0
        def __init__(self):
            self.counter = Field.counter
            Field.counter += 1
    
    0 讨论(0)
  • 2021-01-01 11:34

    You can dig around to find the line number for methods, not sure about other members:

    import inspect
    
    class A:
        def one(self):
            pass
    
        def two(self):
            pass
    
        def three(self):
            pass
    
        def four(self):
            pass
    
    def linenumber_of_member(m):
        try:
            return m[1].__func__.__code__.co_firstlineno
        except AttributeError:
            return -1
    
    a = A()
    l = inspect.getmembers(a)
    print(l)
    l.sort(key=linenumber_of_member)
    print(l)
    

    prints:

    [('__doc__', None), ('__module__', '__main__'), ('four', <bound method A.four of <__main__.A instance at 0x0179F738>>), ('one', <bound method A.one of <__main__.A instance at 0x0179F738>>), ('three', <bound method A.three of <__main__.A instance at 0x0179F738>>), ('two', <bound method A.two of <__main__.A instance at 0x0179F738>>)]
    [('__doc__', None), ('__module__', '__main__'), ('one', <bound method A.one of <__main__.A instance at 0x0179F738>>), ('two', <bound method A.two of <__main__.A instance at 0x0179F738>>), ('three', <bound method A.three of <__main__.A instance at 0x0179F738>>), ('four', <bound method A.four of <__main__.A instance at 0x0179F738>>)]
    
    0 讨论(0)
  • 2021-01-01 11:41
    members = []
    for name, obj in inspect.getmembers(module):
        source, start_line = inspect.getsourcelines(obj)
        members.append([name, obj, start_line])
    
    def _line_order(value):
        return value[2]
    
    members.sort(key = _line_order)
    
    0 讨论(0)
  • 2021-01-01 11:46

    The attributes (methods and other members) of an object is usually looked up through an object's special __dict__ attribute which is a standard Python dictionary. It doesn't guarantee any specific ordering.

    If an attribute is not found in the object's __dict__ the class's is searched instead (where methods usually reside) and so on until the whole inheritance chain has been traversed.

    Here is some custom inspection done in the interactive prompt to illustrate this (Python 3.1):

    >>> class Klass():
    ...     def test(self):
    ...             pass
    ...
    >>> k = Klass()
    >>> k.__dict__
    {}
    >>> k.__class__.__dict__.items()
    [('test', <function test at 0x00000000024113C8>), ('__dict__', <attribute '__dic
    t__' of 'Klass' objects>), ('__module__', '__main__'), ('__weakref__', <attribut
    e '__weakref__' of 'Klass' objects>), ('__doc__', None)]
    

    Would I have put a constructor (__init__) in Klass and set an attribute through self it would've shown up in k.__dict__.

    You can circumvent this by using a custom metaclass. The documentation contains an example which does exactly what you want.

    See the bottom of this page for the OrderedClass example.

    Don't know what version of Python you have so I assumed latest.

    0 讨论(0)
  • 2021-01-01 11:48

    You can use the builtin function vars() as an alternative for inspect.getmembers that returns members in the order they were defined:

    >>> class RegisterForm:
    ...     username = ""
    ...     password1 = ""
    ...     password2 = ""
    ...     first_name = ""
    ...     last_name = ""
    ...     address = ""
    ...
    >>> list(vars(RegisterForm).keys())
    ['__module__', 'username', 'password1', 'password2', 'first_name', 'last_name', 'address', '__doc__']
    

    This works starting with CPython 3.6 and all other Python implementations starting with Python 3.7, because dicts are now ordered by insertion, which means the underlying __dict__ property of a class (which is what vars() returns) is ordered.

    0 讨论(0)
  • 2021-01-01 11:51

    In reference to Ned Batchelder's answer above, in Python 3 line numbers of a method m can be gotten with m.__func__.__code__.co_firstlineno

    inspect — Inspect live objects

    0 讨论(0)
提交回复
热议问题