Ввод данных в словарь

Итак, у меня есть текстовый файл, например:

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

2 ответа

Решение

Это будет хорошо делать:

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

В вашем коде есть несколько разных ошибок. То, что вызывает ваше исключение, заключается в том, что ваша функция data записывает в глобальную переменную и ничего не возвращает, но ваш более поздний код ожидает, что он вернет что-то итерируемое, например последовательность или генератор.

Вы можете исправить это, либо сделав код верхнего уровня итерацией непосредственно в глобальном словаре, либо вы можете избавиться от глобального и создать словарь в data и верните его в конце. Я предлагаю последнее, поскольку с глобальными переменными трудно иметь дело, так как ваш код становится все сложнее.

Вот примерный план того, как это должно работать (я оставляю среднюю часть отрывочной, так как я буду обсуждать это позже):

def data(file):
    objects = {}

    # add stuff to objects dict

    return objects

Ваша следующая ошибка заключается в удалении ваших строк. Ваш код в настоящее время проверяет каждую строку на наличие неравенства strip метод. Это ошибка в Python 3, так как line а также line.strip имеют несравненные типы. Но даже если бы это сработало, это было бы бессмысленно. Я подозреваю, что вы пытались убрать пустые строки, сначала удалив их, а потом отвергнув все пустые. Вот как вы можете это сделать:

if not line.strip():
    continue

Это пример того, что некоторые люди в сообществе Python называют стилем программирования "смотри, прежде чем прыгнуть" (LBYL), так как вы проверяете что-то, что может быть проблемой, прежде чем это станет. Альтернативой является стиль "проще просить прощения, чем разрешения" (EAFP), когда вы просто оборачиваете область, где проблема может возникнуть в try заблокировать и перехватить сгенерированные исключения. Стиль EAFP иногда считается более "питоническим", поэтому я покажу этот стиль чуть позже.

Следующая ошибка - логическая, а не та, которая вызовет ошибку. Вы разбиваете свою строку и хотите получить две ее части в переменных key а также value, Однако вы делаете два отдельных присваивания этим переменным, и на самом деле они заканчиваются одинаковым значением в каждой. Это место, где вы можете использовать классную функцию синтаксиса Python - распаковку. Вместо того, чтобы назначать каждую переменную отдельно, вы можете назначить двухзначную последовательность (например, список или кортеж) для них обоих вместе. Python позаботится о присвоении первого значения первой переменной и второго значения второй переменной. Вот как это выглядит:

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

Конечно, это не удастся, если в строке нет двоеточия, поэтому это хорошее место для нас try блок, если мы используем EAFP-стиль кодирования. Вот один из способов сделать это:

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

Вы могли бы вместо этого поставить try блок вокруг всего, что остается в цикле, а затем пусть except блок содержит только pass (который ничего не делает, но игнорирует исключение).

Наконец, последняя логическая ошибка, которую вы имеете, связана с тем, как вы строите свои вложенные словари. Ваш текущий подход заключается в том, чтобы сначала создать один словарь со всеми ключами и значениями из вашего файла, а затем разделить их на отдельные части, по одному на небесный объект. Однако это не работает, если ключи для каждого объекта одинаковы. Так как, например, у каждого объекта есть ключ "Орбитальный радиус", все они будут писать друг над другом, помещая этот ключ в один словарь.

Ответ @sudo_o показывает, как построить внутренний словарь и заполнить его значениями (это почти идентично тому, что я собирался написать). Я просто хотел опубликовать остальные мои объяснения!

Другие вопросы по тегам