【问题标题】:Accessing a dictionary as attributes of a custom class [duplicate]访问字典作为自定义类的属性[重复]
【发布时间】:2021-11-26 19:31:19
【问题描述】:

这更容易用一个例子来解释。想象一下我有以下字典..

myapps = {'app_1': {'username': 'admin',
                    'pwd': 'S3cret',
                    'ports': [8080, 443],
                    'users': {'user1': 'john',
                              'user2': 'ruth'}},
          'app_2': {'username': 'user1', 
                    'pwd': 'P@ssword'}
}

现在我想通过以下方式使用这本词典的数据:

print("App_2 username = ", myapps.app_2.username) # prints App_2 username = user1
print("App_2 pwd = ",      myapps.app_2.pwd)      # prints App_2 pwd = P@ssword
print("App_1 ports = ",    myapps.app_1.ports)    # prints App_1 ports = [8080, 443]

myapps.app_2.username = "MyNewAdminAccount"
print("App_2 username = ", myapps.app_2.username) # prints App_2 username = MyNewAdminAccount

我基本上是在尝试编写一个可以接受字典的类,递归地遍历它并为我的字典中给出的每个键和子键生成属性。

【问题讨论】:

标签: python


【解决方案1】:

如果我正确理解您的问题,您正在寻找 DotDict: Recursive DotDict

通过这个类,您可以重新映射__getattr__ 和_setattr__,它们在点运算符上被调用以使用访问字典数据的__getitem__ 和__setitem__ 函数。

【讨论】:

  • 谢谢。 Prodict 可以满足我的需要,甚至更多。以前从未听说过那个包。
  • 不客气!它回答了你的问题,但我不确定这是否是最好的方法,因为我真的不知道你的用例,即你是自己构建这些字典还是将它们作为输入等等。所以一般来说,如果你完全控制代码和数据我也会使用数据类(推荐below,但不使用向导,只需自己创建实例)。如果您还没有听说过数据类,我可以推荐这个 youtube 频道:youtube.com/watch?v=vRVVyl9uaZc
  • 如果您不想使用数据类,也可以使用支持此用例的pydantic。它还具有 Secret... 等字段类型,可用于屏蔽密码数据,因此您在记录数据时不会意外泄漏它。但我同意这个问题总体上有点含糊。
【解决方案2】:

对于提供类型提示和自动完成的更“IDE 友好”选项,我建议为此查看Dataclass Wizard 库。只是一个免责声明,它仍处于测试版,因为我正在测试一些东西,但它似乎应该适用于这个用例。

第 1 步:为上述数据生成模型

您可以使用包含的 CLI 实用程序来执行此操作,因为它更容易,但也有一种简单的方法可以以编程方式执行此操作:

from dataclass_wizard.wizard_cli import PyCodeGenerator


string = """
{
  "myapps": {
    "app_1": {
      "username": "admin",
      "pwd": "S3cret",
      "ports": [
        8080,
        443
      ],
      "users": {
        "user1": "john",
        "user2": "ruth"
      }
    },
    "app_2": {
      "username": "user1",
      "pwd": "P@ssword"
    }
  }
}
"""

print(PyCodeGenerator(file_contents=string).py_code)

第 2 步:将数据加载到模型中

from dataclasses import dataclass
from typing import List

from dataclass_wizard import JSONWizard


@dataclass
class Data(JSONWizard):
    """
    Data dataclass

    """
    myapps: 'Myapps'


@dataclass
class Myapps:
    """
    Myapps dataclass

    """
    app_1: 'App1'
    app_2: 'App2'


@dataclass
class App1:
    """
    App1 dataclass

    """
    username: str
    pwd: str
    ports: List[int]
    users: 'Users'


@dataclass
class Users:
    """
    Users dataclass

    """
    user1: str
    user2: str


@dataclass
class App2:
    """
    App2 dataclass

    """
    username: str
    pwd: str

data = Data.from_json(string)

repr(data)
# Data(myapps=Myapps(app_1=App1(username='admin', pwd='S3cret', ports=[8080, 443], users=Users(user1='john', user2='ruth')), app_2=App2(username='user1', pwd='P@ssword')))

现在您可以按预期使用点 . 访问权限。属性的类型提示也应该适用于您的 IDE(至少在 Pycharm 中)

myapps = data.myapps

print("App_2 username = ", myapps.app_2.username) # prints App_2 username = user1
print("App_2 pwd = ",      myapps.app_2.pwd)      # prints App_2 pwd = P@ssword
print("App_1 ports = ",    myapps.app_1.ports)    # prints App_1 ports = [8080, 443]

myapps.app_2.username = "MyNewAdminAccount"
print("App_2 username = ", myapps.app_2.username) # prints App_2 username = MyNewAdminAccount

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-12
    • 2012-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多