Python相当于Java的getClass().getFields()

Python equivalent of Java's getClass().getFields()

我将一段代码从Java转换为Python,我不知道如何翻译以下内容:

1
2
3
Field[] fields = getClass().getFields();
    for (int i = 0; i < fields.length; i++ ) {
        if (fields[i].getName().startsWith((String) param){ ....


在python中,可以查询对象与__dict__的绑定,例如:

1
2
3
4
5
>>> class A:
...     def foo(self): return"bar"
...
>>> A.__dict__
{'__module__': '__main__', 'foo': <function foo at 0x7ff3d79c>, '__doc__': None}

另外,这也是从C的角度提出的:如何在Python中枚举对象的属性?

您可以使用inspect.getmembers(object[,predicate]),而不是直接使用__dict__,它具有像inspect.ismethod(object)这样有用的方法。


首先,我要强调的是,在python中没有像getClass().getFields()这样的东西,因为一个对象可以有许多字段不是由类定义的。实际上,要在python中创建一个字段,只需要为它赋予一个值。未定义字段,将创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> class Foo(object):
...     def __init__(self, value):
...         # The __init__ method will create a field
...         self.value = value
...
>>> foo = Foo(42)
>>> foo.value
42
>>> # Accessing inexistent field
... foo.another_value
Traceback (most recent call last):
  File"<stdin>", line 2, in <module>
AttributeError: 'Foo' object has no attribute 'another_value'
>>> # Creating the field
... foo.another_value = 34
>>> # Now I can use it
... foo.another_value
34

所以,您不能从类中获取字段。相反,您可以从对象中获取字段。

另外,python方法只是具有一些特殊值的字段。方法只是函数的实例:

1
>>> type(foo.__init__)

需要注意的是,为了清楚地表明,在python中没有像getClass().getMethods()这样的方法,并且getClass().getFields()的"等效"也将返回方法。

也就是说,如何获得字段(或属性,正如在Python中经常调用的那样)?当然,您不能从类中获取它们,因为对象存储它们。因此,可以使用dir()函数获取对象属性的名称:

1
2
3
4
5
>>> dir(foo)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__',
 '__getattribute__', '__hash__', '__init__', '__module__', '__new__',
 '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
 '__str__', '__subclasshook__', '__weakref__', 'another_value', 'value']

一旦获得了属性名,就可以使用getattr()函数来获取每个属性名:

1
2
>>> getattr(foo, 'value')
42

要获得所有这些信息,可以使用列表理解:

1
2
3
4
5
6
>>> [getattr(foo, attrname) for attrname in dir(foo)]
[<class '__main__.Foo'>, <method-wrapper '__delattr__' of Foo object at 0x2e36b0>,
 {'another_value': 34, 'value': 42}, None, <built-in method __format__ of Foo object at 0x2e36b0>,
 <method-wrapper '__getattribute__' of Foo object at 0x2e36b0>,
 ... # Lots of stuff
 34, 42]

最后,您可以找到在某些属性上设置的值。

但是,此列表也将包含方法。记住它们也是属性。在这种情况下,我们可以使列表理解避免可调用的属性:

1
2
>>> [attrname for attrname in dir(foo) if not callable(getattr(foo, attrname))]
['__dict__', '__doc__', '__module__', '__weakref__', 'another_value', 'value']

现在,获取实际值:

1
2
3
>>> [getattr(foo, attrname) for attrname in dir(foo)
...      if not callable(getattr(foo, attrname))]
[{'another_value': 34, 'value': 42}, None, '__main__', None, 34, 42]

还有一些奇怪的值,比如__dict____doc__等,它们是一些你可能想忽略的东西。如果是这样,只需在你的列表理解中加入另一个标准:

1
2
3
4
5
6
7
8
>>> [attrname for attrname in dir(foo)
...     if not attrname.startswith('__') and
...         not callable(getattr(foo, attrname))]
['another_value', 'value']
>>> [getattr(foo, attrname) for attrname in dir(foo)
...     if not attrname.startswith('__') and
...         not callable(getattr(foo, attrname))]
[34, 42]

还有其他方法可以做到这一点。例如,可以查看对象的__dict____slots__属性。然而,我发现我提出的方法对初学者来说更清晰。

再编辑两个点。首先,cls解决方案非常好,因为它建议您查看inspect模块。

另外,您可能需要同时获取属性的名称和值。您可以让它生成一个元组列表:

1
2
3
4
>>> [(attrname, getattr(foo, attrname)) for attrname in dir(foo)
...     if not attrname.startswith('__') and
...         not callable(getattr(foo, attrname))]
[('another_value', 34), ('value', 42)]

幸运的是,cls建议的inspect.getmembers()函数做得更好。

1
2
3
4
5
>>> import inspect
>>> inspect.getmembers(foo)
[('__class__', <class '__main__.Foo'>),
 # ... Lots of stuff ...
 ('another_value', 34), ('value', 42)]

要删除方法,只需避免调用:

1
2
>>> inspect.getmembers(foo, lambda attr: not callable(attr))
[('__dict__', {'another_value': 34, 'value': 42}), ('__doc__', None), ('__module__', '__main__'), ('__weakref__', None), ('another_value', 34), ('value', 42)]

(不幸的是,inspect.ismethod()没有按我的预期工作。)

还有很多内部的东西,我们不能像处理方法那样直接出来。列表理解无法再次解决的问题:

1
2
3
>>> [(name, value) for name, value in inspect.getmembers(foo, lambda attr: not callable(attr))
...         if not name.startswith('__')]
[('another_value', 34), ('value', 42)]

Python是一种非常动态的语言,在某些情况下,这个解决方案不能很好地工作。考虑到有可能有一个对象,该对象应该存储一个要在某个地方使用的函数。函数是一个可调用的对象,不会显示属性。但是,它在逻辑上是一个属性,一个要使用的数据。你应该记住这种东西。不过,我敢打赌你不会经常遇到这样的问题。

高温高压


这不是一个确切的等价物,但是dir(self)应该可以让你开始。