【问题标题】:How to get attributes of a class without knowing their names如何在不知道类名的情况下获取类的属性
【发布时间】:2025-12-09 21:40:01
【问题描述】:

我有以下课程:

class TestClass(object):
def __init__(self, **kwargs):
    for key, value in kwargs.items(): #items return list of dict
        setattr(self, key, value)

使用示例:

obj = MessageItem(**{"testkey1":"tval1", "tkey2":"tval2", "tkey3":"tval3"})

如何在不知道属性名称的情况下迭代此结构? Python为我们提供了内置方法__getattribute__,但我还是需要知道请求属性的名称:

print(obj.__getattribute__("testkey1"))

【问题讨论】:

  • 为什么要故意将自己置于这种情况而不是将其存储为dict
  • @JonClements Personaly,我不知道,我的领导是这样计划的,我必须实施:D
  • 好吧,随时告诉他们这不是好的设计,而且有点危险......人们将能够破坏你已经使用过的名称并破坏事物并稍后对其进行调试太可怕了。
  • (或者相反,您可能会破坏对他们传递的变量的赋值......)
  • 请注意(除此之外,在大多数用例中这是一个坏主意):你不会真的想使用 obj.__getattribute__("testkey1") - 你会使用 getattr(obj, 'testkey1') - 不仅是在眼睛和键盘上更容易,它还允许提供默认值以在未找到属性时返回。

标签: python


【解决方案1】:

__dict__ 属性包含您想要的内容。 类有它:

>>> class Foo:
...     def __init__(self, x):
...             self.x = x
...
>>> Foo.__dict__
mappingproxy({'__module__': '__main__', '__init__': <function Foo.__init__ at
0x000001CC1821EEA0>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__':
<attribute '__weakref__' of 'Foo' objects>, '__doc__': None})

任何实例也有它:

>>> f = Foo(2)
>>> f.__dict__
{'x': 2}

您应该通过vars 内置函数访问此属性。 调用vars(foo) 将返回foo.__dict__。 请参阅此相关帖子:Use __dict__ or vars()?

Documentation for vars:

变量([对象])

为具有__dict__ 属性的模块、类、实例或任何其他对象返回__dict__ 属性。

模块和实例等对象具有可更新的__dict__ 属性;但是,其他对象可能对其有写入限制 __dict__ 属性(例如,类使用types.MappingProxyType 来防止直接更新字典)。

没有参数,vars() 的行为就像locals()。请注意,本地字典仅对读取有用,因为更新了本地 字典被忽略。


此外,我尝试并编写了一个您可能感兴趣的装饰器。 这是一个类装饰器,它将initKwargs 添加到它所装饰的类中。 此外,它还包装了该类的__init__ 方法,以便将接收到的kwargs 字典附加到该类的initKwargs 属性中。

def class_wrapper(cls):
    cls.initKwargs = []
    f = cls.__init__

    def wrapped_init(instance, **kwargs):
        cls.initKwargs.append(kwargs)
        return f(instance, **kwargs)            
    cls.__init__ = wrapped_init

    return cls

@class_wrapper
class Foo:
    def __init__(self, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

演示:

>>> f1 = Foo()
>>> f2 = Foo(a=1, b=2)
>>> f3 = Foo(a=1, b=2, c=3, d=4)
>>> Foo.initKwargs
[{}, {'a': 1, 'b': 2}, {'a': 1, 'b': 2, 'c': 3, 'd': 4}]

我发现这种方法比使用vars 更简洁,因为您知道自己正在访问什么,因为您自己定义了它。 它使您可以更好地控制班级的行为。

【讨论】:

  • 如果你要建议,那么建议使用vars(f) - 几乎不需要在这里直接访问__dict__,它可能并不总是像预期的那样。
  • @JonClements 考虑到文档中关于vars 的说法,它与__dict__ 有何不同?我想我记得读到 __dict__ 不太好,但我不记得为什么......
  • 我不记得 确切地了...但是vars(...) 会做正确的事情,而直接访问__dict__ 可能会失败。虽然我现在有点怀疑自己......但有些事情敲响了:) 此外 - 至少 - 在你的代码中没有必要的 dunder 方法访问总是好的。
  • @JonClements 我找到了this post。所以基本上争论是因为 Python 为它提供了一个包装器,它应该通过那个包装器而不是直接访问。这对我来说很有意义。
  • 不错的发现。谢谢。现在 - 唯一的问题是,除非你拿走已经存在的参数或知道你已经设置的参数,否则你实际上无法知道提供了哪些参数......但是如果 OP 打算采用这种方法,那么,好吧,在他们头上就是这样。
最近更新 更多