This code:
import inspect
class Obj():
def c(self):
return 1
def b(self):
return 2
def a(self):
return 3
o = Obj()
for name, value in inspect.getmembers(o, inspect.ismethod):
print str(value())+" "+name
print:
3 a
2 b
1 c
Because of inspect.getmembers
return all the members of an object in a list of (name, value) pairs sorted by name, as you can read in https://docs.python.org/2/library/inspect.html#inspect.getmembers
But I want to get that list in the same order that the members was written in the code, in other words, the output would be:
1 c
2 b
3 a
Is any way to do that?
Thanks
答案 0 :(得分:1)
创建对象时,它的所有属性都包含在名为__dict__
的对象中的另一个专用属性中,顾名思义它只是一个普通的Python非有序字典,因此它们不能保证是以相同的方式存储它们。当使用__dict__
在getmembers()
中检索值时,Python会在打印时自动重新组织字典,以便具有某种逻辑意义。
要解决此问题,必须采取措施将常规Python字典__dict__
转换为某种有序字典。
这可以通过多种方式完成,为简单起见,我假设您使用的是Python 3。
使用collections
包,您可以获得OrderedDict
,这正是我们针对此类问题所需的技术。准备这个有序字典,用于需要存储有序成员的类的元类,复制成员,最后在想要打印出所述成员时访问这个新OrderedDict
。
这可以在this Stack Overflow answer中看到。
答案 1 :(得分:1)
在cpython
中,代码被编译为VM的字节码。这些函数有一个__code__
属性,它是一个代码对象。代码对象具有co_firstlineno
属性,这是Python源代码中的第一行。 (详见inspect
模块。)
如果您知道您的方法都是源代码,并且您知道使用的是cpython,则可以将其用作排序键。但如果你不了解这些事情,那似乎很不稳定。
members = [ (name,meth) for name, meth in inspect.getmembers(o, inspect.ismethod)]
members = sorted(members, key=lambda t: t[1].__code__.co_firstlineno)
print '\n'.join(m[0] for m in members)
答案 2 :(得分:0)
嗯,这非常hacky,但基本上我直接检查源并使用re
来查找方法名称。但是,这个解决方案非常脆弱,并且它不涉及继承,但它可能适合您。假设我已将类定义保存在名为test.py
的文件中:
>>> import test
>>> import re
>>> findmethods = re.compile(r" def (.+)\(")
>>> findmethods.findall(inspect.getsource(test.Obj))
['c', 'b', 'a']
>>>
答案 3 :(得分:0)
没有。班级成员不订购。他们被收集到字典中,立即失去秩序。您可以采用解析源代码等技巧,但它很容易破解。对于初学者来说,来源无法使用。
[编辑:似乎python3在类创建方面允许更多的灵活性,使customize the way class members are gathered成为可能,如果你只使用python3,那可能是更好的方法]
如果更改代码不是问题,您可以使用装饰器:
import inspect
def track_order(fn):
fn.order = track_order.idx
track_order.idx += 1
return fn
track_order.idx = 0
class Obj(object):
@track_order
def c(self):
return 1
@track_order
def b(self):
return 2
@track_order
def a(self):
return 3
o = Obj()
methods = sorted((item
for item in inspect.getmembers(o, inspect.ismethod)),
key=lambda item: item[1].order)
for name, value in methods:
print str(value())+" "+name
装饰器为通过它的所有方法添加idx
属性。
这利用了python具有一流功能的事实。
$ python test.py
1 c
2 b
3 a
注意:这是Django用来跟踪表单和模型字段顺序的方法。只是,他们不需要装饰,因为领域'类具有内置的instanciation order属性(名为creation_counter
)。