Python 自省:如何获取对象属性的“未排序”列表?
Posted
技术标签:
【中文标题】Python 自省:如何获取对象属性的“未排序”列表?【英文标题】:Python introspection: How to get an 'unsorted' list of object attributes? 【发布时间】:2010-10-13 00:47:31 【问题描述】:以下代码
import types
class A:
class D:
pass
class C:
pass
for d in dir(A):
if type(eval('A.'+d)) is types.ClassType:
print d
输出
C
D
如何让它按照代码中定义这些类的顺序输出?即
D
C
除了使用inspect.getsource(A) 和解析之外,还有什么办法吗?
【问题讨论】:
你为什么要这样做? django 的表单和模型声明尝试按照输入的顺序进行。然而,属性是实例而不是类声明。我试图弄清楚类声明是否可以如此排序,因为这将有助于自动模板生成。 对于这样一个奇怪的问题,最好解释一下为什么你想做你想做的事情并添加一个 django 标签。 【参考方案1】:class ExampleObject:
def example2():
pass
def example1():
pass
context = ExampleObject
def sort_key(item):
return inspect.findsource(item)[1]
properties = [
getattr(context, attribute) for attribute in dir(context)
if callable(getattr(context, attribute)) and
attribute.startswith('__') is False
]
properties.sort(key=sort_key)
print(properties)
应该打印出来:
[
我也需要将它用于我正在构建的一些编译器,这被证明非常有用。
【讨论】:
【参考方案2】:inspect
模块还具有findsource
功能。它返回定义对象的源代码行和行号的元组。
>>> import inspect
>>> import StringIO
>>> inspect.findsource(StringIO.StringIO)[1]
41
>>>
findsource
函数实际上是在源文件中搜索并在给定类对象时寻找可能的候选对象。
给定一个方法、函数、回溯、框架或代码对象,它只查看(包含的)代码对象的co_firstlineno
属性。
【讨论】:
【参考方案3】:请注意,在检查中已经为您完成了解析 - 请查看 inspect.findsource
,它在模块中搜索类定义并返回源代码和行号。按该行号排序(您可能还需要拆分在单独模块中定义的类)应该给出正确的顺序。
不过,这个函数好像没有文档记录,只是使用正则表达式来查找行,所以可能不太可靠。
另一种选择是使用元类或其他方式来隐式或显式地将信息排序到对象。例如:
import itertools, operator
next_id = itertools.count().next
class OrderedMeta(type):
def __init__(cls, name, bases, dct):
super(OrderedMeta, cls).__init__(name, bases, dct)
cls._order = next_id()
# Set the default metaclass
__metaclass__ = OrderedMeta
class A:
class D:
pass
class C:
pass
print sorted([cls for cls in [getattr(A, name) for name in dir(A)]
if isinstance(cls, OrderedMeta)], key=operator.attrgetter("_order"))
但是这是一个相当侵入性的更改(需要将您感兴趣的任何类的元类设置为 OrderedMeta)
【讨论】:
我喜欢这种方法,但我使用了 inspect.findsource 并选择了 MizardX 的答案【参考方案4】:我并不是想在这里流言蜚语,但是您可以按字母顺序组织源代码中的课程吗?我发现当一个文件中有很多类时,这本身就很有用。
【讨论】:
【参考方案5】:不,您无法按照您要查找的顺序获取这些属性。 Python 属性存储在 dict(读取:hashmap)中,它不知道插入顺序。
另外,我会通过简单地说来避免使用 eval
if type(getattr(A, d)) is types.ClassType:
print d
在你的循环中。请注意,您也可以只遍历 A.__dict__
中的键/值对
【讨论】:
是的,+1 用于使用 getattr 而不是 eval。【参考方案6】:AFAIK,不——没有*。这是因为类的所有属性都存储在字典中(如您所知,字典是无序的)。
*:这实际上可能是可能的,但这需要装饰器或可能的元类黑客攻击。你对其中任何一个感兴趣吗?
【讨论】:
以上是关于Python 自省:如何获取对象属性的“未排序”列表?的主要内容,如果未能解决你的问题,请参考以下文章