【问题标题】:Python equivalent of Java's getClass().getFields()Python 等效于 Java 的 getClass().getFields()
【发布时间】:2011-09-02 15:11:47
【问题描述】:

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

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

【问题讨论】:

  • 我不确定getClass().getFields() 是做什么的,但你看过dir 吗? a = myClass()dir(a)

标签: java python reflection


【解决方案1】:

在 Python 中,您可以使用 __dict__ 查询对象的绑定,例如:

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

此外,这是从 C# 的角度提出的:How to enumerate an object's properties in Python?

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

【讨论】:

  • inspect 模块是一个很好的建议。但是,我不建议使用__dict__,因为对象可以具有由__slots__ 定义的属性。说了这么多,好回答:)
  • 此外,属性不会显示在__dict__ 中,因此即使您不使用__slots__,它也可能会损坏。无论如何,inspect 模块会处理所有这些。
【解决方案2】:

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

>>> 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 方法只是具有一些特殊值的字段。方法只是函数的实例:

>>> type(foo.__init__)

请务必注意,要明确指出 Python 中没有 getClass().getMethods() 这样的方法,getClass().getFields() 的“等效”也将返回方法。

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

>>> 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() 函数获取每个属性名称:

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

要全部获取,可以使用list comprehensions

>>> [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]

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

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

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

现在,获取实际值:

>>> [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__ 等。它们是一些你可能想忽略的东西。如果是这样,只需在您的列表理解中添加另一个标准:

>>> [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 solution 非常好,因为它建议您查看inspect module

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

>>> [(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() 函数做得更好。

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

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

>>> 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() 没有按我的预期工作。)

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

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

Python 是一种非常动态的语言,在某些情况下,此解决方案无法正常工作。考虑到可能有一个对象应该存储要在某处使用的函数。函数是可调用对象,不会显示属性。然而,逻辑上是一个属性,一个要使用的数据。你应该有这样的想法。不过,我敢打赌,您不会经常遇到此类问题。

HTH

【讨论】:

    【解决方案3】:

    这不是完全等价的,但 dir(self) 应该可以帮助您入门。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-26
      • 2016-08-04
      • 1970-01-01
      • 2019-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-29
      相关资源
      最近更新 更多