【问题标题】:Reading YAML files and accessing lists读取 YAML 文件和访问列表
【发布时间】:2018-09-24 01:20:18
【问题描述】:

我目前正在从 .yml 文件中读取数据。文件中包含每个主要条目的以下部分:

- !
  name: Martial Focus
  prerequisites:
    tier1:
      any:
        Attribute:
        - Attribute1:§ 1
        - Attribute2:§ 1
        Feat:
        - Feat1
        Other:
        - Other Prerequisites
  cost:
  - 3
  description: |
    [...]
  effect: |
    [...]

我已经能够读取所有数据,包括“先决条件”,但这里我有一个特殊问题: 在使用其他数据时,我能够访问子列表,这似乎有所不同:

“any:”部分是可选的,所以它也可以说类似

prerequisites:
    tier1:
      Attribute:
      - Attribute1:§ 1
      - Attribute2:§ 1
      Feat:
      - Feat1
      Other:
      - Other Prerequisites

读取 .yml 文件将上面的部分转换为

'prerequisites': {
  'tier1': {
    'any': {
      'Attribute': ['Attribute1:§ 1', 'Attribute2:§ 1'],
      'Feat': ['Feat1'],
      'Other': ['Other Prerequisites']
    }
  }
}

所以在我的代码中,对于每个“tierX”,我检查它是否包含一个键“any:”通过

if 'any' in tier:
  # do the stuff to be done if 'any' exists
else:
  # do the stuff to be done if it doesn't

但这似乎从来都不是真的。由于“Attribute:”、“Feat:”和“Other:”也是可选的,所以我对 if-else-statement 中的那些也做同样的事情,尽管对于那些没有 else-statement 的问题,它们也是同样的问题。 您可以在下面找到我正在使用的代码。自从我今天开始使用 python 以来,它不会是最漂亮的,但我希望你能帮助我:

        prerequisites = ""
        tierNum = 0
        for tier in data['prerequisites']:
            tierNum += 1
            thisTier = ""
            if 'any' in tier:
                print("'any' found!")
                content = tier['any']
                if 'Other' in content:
                    other = ""
                    for s2 in content['Other'][:-1]:
                        other += s2 + ", "
                    thisTier += "**" + other
                    if len(content['Other'][:-1]) == 0:
                        thisTier += str(content['Other'][-1:])
                    else:
                        thisTier += "or " + str(content['Other'][-1:])

                    if 'Attribute' in content:
                        attributes = ""
                        for s2 in content['Attribute'][:-1]:
                            attributes += s2 + ", "
                        if thisTier.length() == 0:
                            thisTier += "**" + attributes
                        else:
                            thisTier += ", or " + attributes
                        if len(content['Attribute'][:-1]) == 0:
                            thisTier += str(content['Attribute'][-1:])
                        else:
                            thisTier += "or " + str(content['Attribute'][-1:])

                    if 'Feat' in content:
                        feats = ""
                        for s2 in content['Feat'][:-1]:
                            feats += s2 + ", "
                        if thisTier.length() == 0:
                            thisTier += "**" + feats
                        else:
                            thisTier += ", or " + feats
                        if len(content['Feat'][:-1]) == 0:
                            thisTier += str(content['Feat'][-1:])
                        else:
                            thisTier += "or " + str(content['Feat'][-1:])

            else:
                content = tier
                if 'Other' in content:
                    other = ""
                    for s2 in content['Other'][:-1]:
                        other +=  s2 + ", "
                    thisTier += "**" + other
                    if len(content['Other'][:-1]) == 0:
                        thisTier += str(content['Other'][-1:])
                    else:
                        thisTier += "or " + str(content['Other'][-1:])

                if 'Attribute' in content:
                    attributes = ""
                    for s2 in content['Attribute'][:-1]:
                        attributes += s2 + ", "
                    thisTier += "**" + attributes
                    if len(content['Attribute'][:-1]) == 0:
                        thisTier += str(content['Attribute'][-1:])
                    else:
                        thisTier += "or " + str(content['Attribute'][-1:])

                if 'Feat' in content:
                    feats = ""
                    for s2 in content['Feat'][:-1]:
                        feats += s2 + ", "
                    thisTier += "**" + feats
                    if len(content['Feat'][:-1]) == 0:
                        thisTier += str(content['Feat'][-1:])
                    else:
                        thisTier += "or " + str(content['Feat'][-1:])

            prerequisites += "*Tier {0}:\n{1}\n".format(tierNum, thisTier)
        prerequisites = prerequisites[:-1]

我正在做类似content['Feat'][:-1] 之类的操作,以便获取除最后一个元素之外的所有元素,因此如果有多个元素,我可以在最后一个元素前添加", or "

编辑: 我想要的输出是这样的:

Prerequisites:
*Tier 1:
**Attribute1 1, or Attribute2 1
**Feat1
**Other Prerequisites

如果不存在并且

Prerequisites:
*Tier 1:
**Attribute1 1, or Attribute2 1, or Feat1, or Other Prerequisites

如果没有

【问题讨论】:

  • 想要的输出是什么?
  • 编辑了我的帖子以包含该内容

标签: python python-3.x if-statement key yaml


【解决方案1】:

您的问题是 for tier in data["predicates"] 遍历谓词字典的 keys,因此后续的 if "any" in tier 实际上评估 "any" in "tier1" 这总是错误的原因。


你想在这里测试的是"any" in data["predicates"]["tier1"]。使用字典(即映射)时,您必须区分 key 及其对应的 value

有趣的是,您已经为下一个级别做好了准备:

# ...
content = tier['any']
if 'Other' in content:
    other = ""
    for s2 in content['Other']:
       # ...

遍历字典的方法

d = {"key1":"value1", "key2":"value2", "key3":"value3"}
for key in d:
  print(key)
# prints key1, key2, key3
for key in d.keys():
  print(key)
# prints key1, key2, key3
for value in d.values():
  print(value)
# prints value1, value2, value3
for item in d.items():
  print(item)
# prints (key1,value1), (key2,value2), (key3,value3)
for key, value in d.items():
  print(key)
  print(value)
# prints key1, value1, key2, value2, key3, value3

请参阅 python 文档 herehere


由于您是 Python 新手并且不知道什么是可能的,请允许我向您展示一个更优雅的解决方案,无需所有重复的字符串操作:

import yaml


yamldata1 = r"""
- !
  name: Martial Focus
  prerequisites:
    tier1:
      any:
        Attribute:
        - Attribute1:§ 1
        - Attribute2:§ 1
        Feat:
        - Feat1
        Other:
        - Other Prerequisites
  cost:
  - 3
  description: |
    [...]
  effect: |
    [...]
"""
yamldata2 = r"""
- !
  name: Martial Focus
  prerequisites:
    tier1:
        Attribute:
        - Attribute1:§ 1
        - Attribute2:§ 1
        Feat:
        - Feat1
        Other:
        - Other Prerequisites
  cost:
  - 3
  description: |
    [...]
  effect: |
    [...]
"""


def process(data):
    output = ""
    for tier_name, tier in data['prerequisites'].items():
        output += f"* {tier_name}"
        if 'any' in tier:
            content = tier['any']
            prerequisites = content.get('Other', []) + content.get('Attribute', []) + content.get('Feat', [])
            if prerequisites:
                output += "\n** " + " or ".join(prerequisites)
        else:
            content = tier
            prerequisites = [content.get('Other', []), content.get('Attribute', []), content.get('Feat', [])]

            for subset in prerequisites:
                if subset:
                    output += "\n** " + " or ".join(subset)
    return output


data = yaml.load(yamldata1)[0]
print(process(data))
print('#'*10)
data = yaml.load(yamldata2)[0]
print(process(data))

【讨论】:

  • 但这就是我想要它做的,不是吗?对于每一层,我想检查那里是否有“任何”键。
  • 我很困惑。这不是for tier in data['prerequisites'] 的用途吗?正确的表达方式是什么?
  • 很抱歉,但我还是不明白我的问题出在哪里._.
  • 我不是用我的if 'any' in tier 在每一层中寻找一个名为“any”的密钥吗?
  • data['prerequisites'] 是字典而不是列表!如果您遍历字典,您实际上会遍历其键,因此您的 tier 变量将包含字符串 "tier1" 而不是数据结构的相应部分,即 data['prerequisites']['tier1']
猜你喜欢
  • 2019-11-06
  • 2019-07-30
  • 2023-03-03
  • 2023-03-21
  • 2020-08-07
  • 2015-09-05
  • 2020-06-21
  • 2019-01-09
  • 2015-04-22
相关资源
最近更新 更多