【问题标题】:Inputting data into dictionary将数据输入字典
【发布时间】:2012-11-22 20:03:46
【问题描述】:

所以我有一个文本文件,例如:

RootObject: Sun

Object: Sun
Satellites: Mercury,Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune,Ceres,Pluto,Haumea,Makemake,Eris
Radius: 20890260
Orbital Radius: 0

Object: Earth
Orbital Radius: 77098290
Period: 365.256363004
Radius: 6371000.0
Satellites: Moon

Object: Moon
Orbital Radius: 18128500
Radius: 1737000.10
Period: 27.321582

我正在尝试将其输入字典。这是我到目前为止所拥有的,但我不断收到错误...

#d = dictionary
#new_d = new dictionary

file = open("data.txt","r")
d = {}
def data(file):
    for line in file:
        if line != line.strip:
            continue
        line = line.strip()
        key = line.split(":")
        val = line.split(":")
        if key in d and key == "Object":
            print(d)
        d[key] = val
    print(d)

new_d = {}
with file as x:
    for d in data(x):
        new_d[d["Object"]] = d
print(nd)

我应该得到这样的东西:

{' Earth': {'Satellites': ' Moon', 'Orbital Radius': ' 77098290', 'Object': ' Earth', 'Radius': ' 6371000.0', 'Period': ' 365.256363004'}, ' Moon': {'Orbital Radius': ' 18128500', 'Object': ' Moon', 'Radius': ' 1737000.10', 'Period': ' 27.321582'}, ' Sun': {'Satellites': ' Mercury,Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune,Ceres,Pluto,Haumea,Makemake,Eris', 'Orbital Radius': ' 0', 'Object': ' Sun', 'Radius': ' 20890260', 'RootObject': ' Sun'}}

我收到此错误:

Traceback (most recent call last):
  File "planet2.py", line 21, in <module>
    for d in data(x):
TypeError: 'NoneType' object is not iterable

【问题讨论】:

  • 您遇到的错误是什么?如果您在问题中包含完整的回溯,它将帮助我们帮助您进行调试。
  • 哦,对了,对不起。我现在添加了错误。
  • 这是家庭作业吗,@Artorius?我正在写一个答案,但如果这是你应该学习的东西,我不想为你做太多的工作。
  • 是的。我已经有了答案,但我想让它更简单,这就是我在上面遇到错误时所尝试的......@Blckknght
  • 基本上我正在寻找最简单的代码来做同样的事情。我不确定这是否可能,或者我在这里写的代码是否已经足够了。

标签: python python-3.x dictionary input


【解决方案1】:

这会很好:

file = open("data.txt","r")

def data(file):
    dic = {}
    for line in file:
        # If line not blank
        if line.strip() != '':
            key,value = line.split(":")
            if key == 'RootObject':
                dic[key] = value.strip()
            elif key == 'Object':
                # Get the Object value i.e Earth, Moon, Sun                
                obj = value.strip()
                # Create entry with obj key and blank dictionary value
                dic[obj]={}
            else:
                # Populate the blank dictionary with key, value pairs
                dic[obj][key] = value.strip()
    return dic

planets = data(file)

# Usage
print planets
print planets['Earth']
print planets['Earth']['Radius']

输出:

# The whole dictionary 
{'Sun': {'Satellites': 'Mercury,Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune,Ceres,Pluto,Haumea,Makemake,Eris', 'Orbital Radius': '0', 'Radius': '20890260'}, 'Moon': {'Orbital Radius': '18128500', 'Radius': '1737000.10', 'Period': '27.321582'}, 'Earth': {'Satellites': 'Moon', 'Orbital Radius': '77098290', 'Radius': '6371000.0', 'Period': '365.256363004'}}

# The Earth dictionary
{'Satellites': 'Moon', 'Orbital Radius': '77098290', 'Radius': '6371000.0', 'Period': '365.256363004'}

# The Earth's radius
6371000.0

【讨论】:

  • 您是否需要 () 围绕打印的对象?像打印(行星)
  • 你在 Python 3 中做,而不是在 Python 2 中。我假设你们两个使用不同的版本。
  • 我正在运行 2.*,不知道 3.* 不能向后兼容,感谢@Blckknght 的提醒
  • 是的,这是 2.x 和 3.x 之间最明显的变化之一。 Print 变成了一个函数,而不是一个语句。不过这有点好,因为您可以将print 作为参数传递给map 之类的东西,甚至可以在其位置分配一个新函数。
  • @Romulus 我做了一个小编辑以包含RootObject,您将需要它来进行递归打印。
【解决方案2】:

您的代码中有几个不同的错误。导致您的异常的原因是您的函数 data 写入全局变量并且不返回任何内容,但是您以后的代码希望它返回可迭代的内容,例如序列或生成器。

您可以通过使顶级代码直接在全局字典上迭代来解决此问题,或者您可以摆脱全局并在 data 中创建字典并在最后返回它。我建议后者,因为随着代码变得越来越复杂,全局变量很难处理。

这里是它应该如何工作的粗略大纲(我将中间部分粗略地留下,因为我稍后会讨论它):

def data(file):
    objects = {}

    # add stuff to objects dict

    return objects

你的下一个错误是剥离你的线条。您的代码当前使用自己的 strip 方法测试每一行的不等式。这是 Python 3 中的一个错误,因为 lineline.strip 具有无法比较的类型。但即使有效,也毫无意义。我怀疑你试图消除空行,首先剥离它们,然后拒绝任何空行。您可以这样做:

if not line.strip():
    continue

这是 Python 社区中的一些人所说的“跳前检查”(LBYL) 编程风格的一个示例,因为您正在检查可能存在问题的东西,然后才成为问题。另一种选择是“请求宽恕比许可更容易”(EAFP)样式,您只需将可能出现问题的区域包裹在try 块中并捕获生成的异常。 EAFP 风格有时被认为更“Pythonic”,所以我稍后会展示这种风格。

下一个错误是一个逻辑错误,而不是会导致错误的东西。您正在拆分您的行,并且您希望将它的两部分放入变量keyvalue。但是,您对这些变量进行了两次单独的赋值,实际上它们最终得到了相同的值。这是一个你可以使用 Python 语法的一个很酷的特性,解包的地方。您可以将一个双值序列(例如列表或元组)一起分配给它们,而不是单独分配每个变量。 Python 将负责将第一个值赋予第一个变量,将第二个值赋予第二个变量。这是它的样子:

key, value = line.split(":")

当然,如果行中没有冒号,这将失败,所以如果我们使用 EAFP 风格的编码,这是放置 try 块的好地方。这是一种方法:

try:
    key, value = line.split(":")
except ValueError:
    continue

您可以改为将try 块放在循环中剩余的所有内容周围,然后让except 块只包含pass(什么都不做,但忽略异常)。

最后,您遇到的最后一个逻辑错误与构建嵌套字典的方式有关。您当前的方法是首先使用文件中的所有键和值构建一个字典,然后将它们分成单独的部分,每个天体一个。但是,如果每个对象的键相同,这将不起作用。例如,由于每个对象都有一个“Orbital Radius”键,因此它们都将相互覆盖,将该键放入单个字典中。

@sudo_o 的回答显示了如何构建内部字典并用值填充它(它几乎与我要写的相同)。我只是想发表其余的解释!

【讨论】:

  • 哦哇非常感谢!这完全有道理!问题,我可以将 Try 语句添加到 Sudo_o 的代码中吗?这会让它在功能上更加正确吗?
  • 一些健全性检查/输入验证总是一件好事,我写代码比散文更好,所以我 +1(在 2 小时内.. 使用我的日常投票哈哈)
  • @Artorius:要使@sudo_o 的代码使用EAFP 样式的错误检查而不是LBYL,请将if line.strip != "" 行替换为try,并在相同的缩进级别添加except ValueError: pass,在在else 块和return 语句之间。
  • @Artorius 因为代码是针对一个特定的结构化文件的,所以我使用的方法是完全可以接受的,但是如果您为具有潜在差异/格式的多个文件编写更通用的代码,那将是一个好主意考虑异常处理(IMO)
  • 两者 - 假设一个值为Object: Cygnus:OB2-12,那么第二个: 将导致ValueError 或者另一个文件使用- 作为分隔符,例如Object- Earth。如果结构与您的示例一致,您将没有问题。
猜你喜欢
  • 2022-07-29
  • 1970-01-01
  • 1970-01-01
  • 2016-01-10
  • 2020-10-24
  • 2021-04-18
  • 2010-11-22
  • 1970-01-01
  • 2018-07-13
相关资源
最近更新 更多