inspect.getmembers按顺序?

时间:2010-07-02 20:47:13

标签: python python-2.6

inspect.getmembers(object[, predicate])
  

返回按名称排序的(名称,值)对列表中对象的所有成员。

我想使用此方法,但我不希望对成员进行排序。我希望它们按照定义的顺序返回。这种方法有替代方法吗?


使用案例

创建一个这样的表单:

class RegisterForm(Form):
    username = Field(model_field='username', filters=validators.minlength(3))
    password1 = Field(model_field='password', widget=widgets.PasswordInput)
    password2 = Field(widget=widgets.PasswordInput)
    first_name = Field(model_field='first_name')
    last_name = Field(model_field='last_name')
    address = SubForm(form=AddressForm, model_field='address')

我希望按照定义的顺序渲染字段。

6 个答案:

答案 0 :(得分:13)

你可以四处寻找方法的行号,不确定其他成员:

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].im_func.func_code.co_firstlineno
    except AttributeError:
        return -1

a = A()
l = inspect.getmembers(a)
print l
l.sort(key=linenumber_of_member)
print l

打印:

[('__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>>)]

答案 1 :(得分:5)

对象的属性(方法和其他成员)通常通过对象的特殊__dict__属性查找,该属性是标准的Python字典。它不保证任何特定的订购。

如果在对象的__dict__中找不到属性,则会搜索类(通常驻留方法),依此类推,直到遍历整个继承链为止。

这是在交互式提示中完成的一些自定义检查,以说明这一点(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)]

我是否在Klass中放置了一个构造函数(__init__)并通过self设置了一个属性,它将显示在k.__dict__中。

您可以使用自定义元类来规避这一点。该文档包含一个完全符合您要求的示例。

请参阅本页底部的OrderedClass example

不知道你有什么版本的Python,所以我认为最新。

答案 2 :(得分:3)

我认为Python 2.6没有__prepare__方法,所以我无法将默认的dict替换为有序的方法。但是,我可以使用metaclass__new__方法替换它。我没有检查行号,而是认为使用创建计数器更容易,更有效。

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

答案 3 :(得分:1)

关于Ned Batchelder上面的答案,在Python 3中,方法m的行号可以通过m.__func__.__code__.co_firstlineno获得

https://docs.python.org/3/library/inspect.html

答案 4 :(得分:1)

您可以使用内置函数vars()替代inspect.getmembers,该函数按定义的顺序返回成员:

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

此功能从CPython 3.6开始,以及从Python 3.7开始的所有其他Python实现,因为dict现在通过插入进行排序,这意味着类的基础__dict__属性({ {1}}返回)。

答案 5 :(得分:0)

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)