【问题标题】:How to list all fields of a class (and no methods)?如何列出一个类的所有字段(没有方法)?
【发布时间】:2014-03-23 14:17:30
【问题描述】:

假设o 是一个Python 对象,我想要o 的所有字段,没有任何方法或__stuff__。如何做到这一点?

我尝试过类似的方法:

[f for f in dir(o) if not callable(f)]

[f for f in dir(o) if not inspect.ismethod(f)]

但是这些返回与dir(o) 相同,大概是因为dir 给出了一个字符串列表。另外,__class__ 之类的东西会在这里返回,即使我让它工作了。

【问题讨论】:

标签: python python-2.7 introspection


【解决方案1】:

您可以通过__dict__ 属性或built-in vars 函数获取它,这只是一个快捷方式:

>>> class A(object):
...     foobar = 42
...     def __init__(self):
...         self.foo = 'baz'
...         self.bar = 3
...     def method(self, arg):
...         return True
...
>>> a = A()
>>> a.__dict__
{'foo': 'baz', 'bar': 3}
>>> vars(a)
{'foo': 'baz', 'bar': 3}

只有对象的属性。方法和类属性不存在。

【讨论】:

  • 这是每个实例。
  • 这可能是您将获得的最佳近似值,但应该注意的是,这将可调用实例属性(有时使用并且实际上类似于方法)视为非方法并考虑类没有对应实例属性的属性不是字段(即使它在大多数情况下都像一个字段)。它还会忽略属性并在带有__slots__ 的类上失败,这可能很重要,也可能无关紧要。
  • 如果 __dict __ 未定义,也不起作用。并非总是如此。
  • slots 并不总是包含您要查找的所有内容。
【解决方案2】:

您可以使用内置方法vars()

【讨论】:

  • 我赞成在 Python 中调用其他方法而不是损坏的魔法方法和属性。我认为这是更 Pythonic 的方式。所以,接受我的 +1。
  • 回溯(最近一次调用最后一次):文件“”,第 1 行,在 类型错误:vars() 参数必须具有 dict 属性
  • @JohnSohn 很难从错误消息中找出问题,但它告诉我们传递给 vars() 的任何内容都没有 __dict__ 属性,表明传递的内容可能不是object。事实上,a = "text"; vars(a) 我们也收到了类似的信息。
【解决方案3】:

基本答案是“你不能可靠地做到这一点”。见this question

您可以使用[attr for attr in dir(obj) if attr[:2] + attr[-2:] != '____' and not callable(getattr(obj,attr))] 获得近似值。

但是,你不应该依赖这个,because

因为提供dir() 主要是为了方便在交互式提示中使用,它试图提供一组有趣的名称,而不是提供一组严格或一致定义的名称,并且它的详细行为可能会改变跨版本。

换句话说,没有规范的方法来获取“对象的所有属性”(或“对象的所有方法”)的列表。

如果您正在执行某种动态编程,需要您遍历对象的未知字段,那么唯一可靠的方法是实现您自己的方式来跟踪这些字段。例如,您可以使用属性命名约定、特殊的“字段”对象,或者最简单的字典。

【讨论】:

  • 我不确定,但如果您可以创建自己的成员并用双下划线括起来,这将会中断。
  • @2rs2ts:是的,确实如此。没有办法解决这个问题。没有办法以编程方式判断双下划线名称是否“神奇”;你必须阅读文档。
  • 这些是命名约定,您不应该通过用双下划线将它们括起来来创建自己的成员。
  • @Benjamin:确实。在PEP 8 - Style Guide for Python CodeDescriptive: Naming Styles 部分的末尾,关于带有双下划线前缀和后缀的名称,它说“永远不要发明这样的名称;只按照文档说明使用它们。”
  • 我开始发现自己同意这一点。
【解决方案4】:

这应该适用于可调用对象:

[f for f in dir(o) if not callable(getattr(o,f))]

您可以通过以下方式摆脱其余部分:

[f for f in dir(o) if not callable(getattr(o,f)) and not f.startswith('__')]

【讨论】:

  • 差不多。我得到了['__dict__', '__doc__', '__module__', '__weakref__', 'a', 'b'] 和一个以ab 作为班级成员的虚拟班级。
  • 关闭,但仍包括__dict____doc__
  • 我会添加这个。[f for f in dir(m) if not callable(getattr(m,f)) and not f.startswith('__')]
【解决方案5】:

您可以遍历实例的__dict__ 属性并查找非方法的东西。 例如:

CALLABLES = types.FunctionType, types.MethodType
for key, value in A().__dict__.items():
    if not isinstance(value, CALLABLES):
        print(key)

输出:

foo
bar

您可以在单个语句中使用list comprehension

print([key for key, value in A.__dict__.items() if not isinstance(value, CALLABLES)])

这将打印['foo', 'bar']

【讨论】:

  • 没有必要过滤掉方法,因为它们在__dict__类中,而不是__dict__s实例中。
  • @Blckknght:我进行了测试,因为类也是一个对象。但是,在您发表评论后,我意识到需要检查一种类型的可调用对象,并修改了我的答案。谢谢。如果可以假设该对象是一种新型类实例,那么您所说的是正确的,并且可以简化for 循环。
猜你喜欢
  • 2019-11-04
  • 1970-01-01
  • 2016-08-30
  • 2012-10-22
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 2014-01-12
相关资源
最近更新 更多