【问题标题】:Mapping dict items on class attributes在类属性上映射 dict 项
【发布时间】:2013-04-18 21:17:39
【问题描述】:

类实例的__dict__ 属性对于将给定的dict 对象映射到类实例非常有用(dict 的键在进程中成为类实例属性)。

例子:

>>> class SomeClass(object):
...     def __init__(self):
...         self.numbers = [1, 3, 5, 7, 9]
... 
>>> inst = SomeClass()
>>> inst.__dict__
{'numbers': [1, 3, 5, 7, 9]}
>>> inst.__dict__.update({
...     'letters': ['a', 'b', 'c', 'd'],
...     'numbers': [2, 4, 6, 8, 10]
...     })
>>> inst.letters, inst.numbers
(['a', 'b', 'c', 'd'], [2, 4, 6, 8, 10])

但是,如果类属性声明如下:

>>> class SomeClass(object):
...     numbers = [1, 3, 5, 7, 9]
... 
>>> inst = SomeClass()
>>> inst.__dict__
{}

在这种情况下有没有办法访问它们?我的意思是,有没有办法独立于其他特殊类属性(例如方法或默认属性)列出它们?

【问题讨论】:

    标签: python class dictionary


    【解决方案1】:

    这些是 class 属性,而不是实例属性。类属性在实例之间共享。这也是实例如何继承其类的方法的方式。实例属性具有同名的影子类属性,因此您可以在实例上设置numbers 以赋予实例自己的副本。

    您可以在实例上使用dir() 来列出实例和类属性名称的组合视图:

    >>> inst = SomeClass()
    >>> dir(inst)
    ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'numbers']
    

    您可以使用inspect.getmembers() 来过滤属性的类型。

    另一种选择是使用__dict__ 列出class 属性:

    >>> vars(type(inst))
    dict_proxy({'__dict__': <attribute '__dict__' of 'SomeClass' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'SomeClass' objects>, 'numbers': [1, 3, 5, 7, 9], '__doc__': None})
    >>> {k: v for k, v in vars(type(inst)).iteritems() if not k.startswith('__') and not inspect.isfunction(v)}
    {'numbers': [1, 3, 5, 7, 9]}
    

    来自Class definitions documentation

    类定义中定义的变量是类属性;它们由实例共享。实例属性可以在带有self.name = value 的方法中设置。类和实例属性都可以通过符号“self.name”访问,而实例属性在以这种方式访问​​时会隐藏同名的类属性。

    【讨论】:

    • 我知道dir 的事情,但不知道inspect.getmembers。但是,在我的情况下,如果不使用丑陋的 hack,它们似乎都无法使用。
    【解决方案2】:

    我的建议是你应该避免修改__dict__locals()等等。

    为什么不将您期望动态的属性显式存储在字典中?这样一来,您就不会因为没有在类中定义而在其他地方通过代码进行猴子修补而导致一堆具有您不期望的属性的对象。

    我认为这更清晰,更不可怕:

    class MyClass(object):
        classattrs = {'numbers': [1,2,3,4,5]}
    
    MyClass.classattrs['letters'] = ['a','b','c']
    

    归结为人们期望 dict 的内容会改变这一事实。他们不希望类的属性发生变化。

    在任何情况下,inspectdir 和它们的同类将无法过滤掉所有其他类属性,如特殊方法等。

    这种保持名称和属性(合理地)静态的想法已经被比我更聪明、更有经验的人表达了:http://nedbatchelder.com/blog/201112/keep_data_out_of_your_variable_names.html

    【讨论】:

    • 我理解基本原理,但在我的特殊情况下,即时更改属性没有问题。如果我这样做,那是因为我发现它(自相矛盾地)更容易处理。
    • 自己动手吧!如果您想要一个所有非“魔术”属性的列表,您可以尝试使用 inspect.getmembers 过滤掉所有双下划线名称 - 类似于:[name, attr for name, attr in inspect.getmembers(MyClass) if not name.startswith('__') and not inspect.ismethod(attr)]
    • 太可怕了! :) 所以似乎我尝试这样做可能是错误的。我会尝试另辟蹊径。感谢您的建议!
    【解决方案3】:

    如果将numbers定义为类属性,

    class SomeClass(object):
        numbers = [1, 3, 5, 7, 9]
    

    然后放入SomeClass.__dict__:

    In [5]: SomeClass.__dict__
    Out[5]: dict_proxy(
    {'__dict__': <attribute '__dict__' of 'SomeClass' objects>,
     '__module__': '__main__',
     '__weakref__': <attribute '__weakref__' of 'SomeClass' objects>,
     'numbers': [1, 3, 5, 7, 9],
     '__doc__': None})
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-23
      • 1970-01-01
      • 2021-01-24
      • 1970-01-01
      • 1970-01-01
      • 2021-04-30
      • 1970-01-01
      • 2021-02-27
      相关资源
      最近更新 更多