【问题标题】:Problems when converting a dictionary to object将字典转换为对象时的问题
【发布时间】:2014-11-25 10:30:55
【问题描述】:

我正在使用之前讨论过的一种技术,将字典转换为对象,这样我就可以使用点 (.) 概念访问字典的元素,作为实例变量。

这就是我正在做的:

# Initial dictionary
myData = {'apple':'1', 'banana':'2', 'house':'3', 'car':'4', 'hippopotamus':'5'}

# Create the container class
class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

# Finally create the instance and bind the dictionary to it
k = Struct(**myData)

所以现在,我可以做:

print k.apple

结果是:

1

这可行,但是如果我尝试向“Struct”类添加一些其他方法,问题就会开始。例如,假设我正在添加一个仅创建变量的简单方法:

class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

    def testMe(self):
        self.myVariable = 67

如果我这样做:

k.testMe()

我的字典对象损坏了,“myVariable”作为键值被插入,值为“67”。所以如果我这样做:

print k.__dict__

我得到:

{'apple': '1', 'house': '3', 'myVariable': 67, 'car': '4', 'banana': '2', 'hippopotamus': '5'}

有没有办法解决这个问题?我有点理解发生了什么,但不确定是否需要完全改变我的方法并使用内部方法构建一个类来处理字典对象,或者是否有更简单的方法来解决这个问题?

这里是原始链接: Convert Python dict to object?

谢谢。

【问题讨论】:

  • 对象实例的属性存储在所谓的 instance dict 中,可以通过obj.__dict__ 访问 - 您是否故意为您的 dict 选择该名称,因为您希望它“看起来像一个真实的物体”,还是偶然的?因为如果没有,你应该只使用self._dict 之类的东西(先初始化它),你会很好的。
  • 或者换种说法:是的,当然myVariable 是作为您对象的__dict__ 的键插入的——它应该是这样工作的。这不是你想要的吗?我不明白这如何“破坏”你的听写。
  • @LukasGraf 您好,感谢您的及时回复。我刚刚按照该链接中的说明进行操作。让我试试,但我怀疑,如果我不使用__dict__,我将无法获得.item 访问权限。我现在就试试。
  • 不,如果您不使用obj.__dict__,您将无法获得点属性访问权限。但是,您可以使用namedtuple(IIRC 在另一个答案中也有一个示例)。
  • 好吧,我不希望我在类中创建的每个变量都插入到字典中,我希望能够在不污染字典的情况下拥有更多内部功能。当然可以的话?

标签: python class dictionary


【解决方案1】:

为了您的需要,不要将变量存储在__dict__ 中。请改用您自己的字典,并覆盖 .__getattr__(对于 print k.apple)和 __setattr__(对于 k.apple=2):

# Initial dictionary
myData = {'apple':'1', 'banana':'2', 'house':'3', 'car':'4', 'hippopotamus':'5'}

# Create the container class
class Struct:
    _dict = {}
    def __init__(self, **entries):
        self._dict = entries

    def __getattr__(self, name):
        try:
            return self._dict[name]
        except KeyError:
            raise AttributeError(
                "'{}' object has no attribute or key '{}'".format(
                    self.__class__.__name__, name))


    def __setattr__(self, name, value):
        if name in self._dict:
            self._dict[name] = value
        else:
            self.__dict__[name] = value

    def testMe(self):
        self.myVariable = 67

    def FormattedDump(self):
        return str(self._dict)

# Finally create the instance and bind the dictionary to it
k = Struct(**myData)

print k.apple
print k.FormattedDump()
k.testMe()
k.apple = '2'
print k.FormattedDump()

或者,如果您的FormattedDump() 例程困扰着您,您可以修复

# Initial dictionary
myData = {'apple':'1', 'banana':'2', 'house':'3', 'car':'4', 'hippopotamus':'5'}

# Create the container class
class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)
        self.public_names = entries.keys()

    def testMe(self):
        self.myVariable = 67

    def GetPublicDict(self):
        return {key:getattr(self, key) for key in self.public_names}
    def FormattedDump(self):
        return str(self.GetPublicDict())

# Finally create the instance and bind the dictionary to it
k = Struct(**myData)

print k.apple
print k.FormattedDump()
k.testMe()
k.apple = '2'
print k.FormattedDump()

【讨论】:

  • 删除了我的答案以支持你的答案,因为你要扩展 __setattr__
  • 您应该在__getattr__ 中引发AttributeError,否则self._dict 中缺少的键会引发KeyError,这对于点属性访问来说是相当意外的。
  • 嗨!非常感谢你的帮助!我会立即尝试。这看起来已经很酷了,感谢所有帮助和建议。
  • @symbolix - 欢迎您。但请考虑我的第二个选择。如果对我来说似乎更优雅。
  • 当然。这看起来是一种了解更多关于类等的有价值的方法。当我试图利用任何变量来执行操作时,我在我的初始代码中感到非常困惑,因为它被添加到我的字典中。所以作为我出发点的解决方案实际上是错误的?!
猜你喜欢
  • 2018-07-15
  • 2021-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-26
  • 2019-07-21
  • 1970-01-01
相关资源
最近更新 更多