Формат JSON

JSON — это текстовый формат обмена данными, основанный на мультипарадигменном языке программирования. Его основное назначение состоит в хранении и передаче структурированного потока информации.

При помощи простых правил формирования конструкций из символов в JavaScript, человек может обеспечить легкий и надежный способ хранения любого вида информации, будь то обычное число, целые строки или огромное количество различных объектов, выраженных в простом тексте.

Помимо этого, формат JSON используется для объединения между собой объектов и структуры данных в виде набора компонентов, формируя тем самым программные единицы, позволяющие хранить и обрабатывать сложные записи, состоящие из нескольких переменных разного типа.

После того как файл создан, содержащиеся в нем строки довольно легко перенаправить в другое положение Сети через любые пути передачи данных. Это связано с тем, что строка представляет собой обычный текст.

Что значит JSON

Несмотря на возможность использования практически во всех скриптовых языках, его название относится к JavaScript. Инструмент имеет следующие преимущества:

  1. Занимает сравнительно небольшой объем, компактен.
  2. Текстовое содержание может легко создаваться и поддаваться чтению вычислительной техникой и человеком.
  3. Можно без особого труда преобразовать в структуру практически для всех видов формальных языков, использующихся для создания компьютерных программ.
  4. Большинство языков программирования, будь то JavaScript, Ruby, Python или PHP, наделены функциями и специальными инструментами для чтения и редактирования файла.

Как устроен формат JSON

В JSON типы данных подразделяются на несколько категорий: простые и сложные. К первому виду можно отнести, прежде всего, текстовые строки и числа, ко второму — объекты. В общей сложности выделяют шесть основных типов:

  1. Числительный. При этом числа могут быть как беззнаковыми целыми, так и целыми со знаком. В частности, здесь может содержаться дробная часть и представление действительных чисел в виде дробной части логарифма и порядка. Файл одинаково позволяет использование целых чисел и разделение с плавающей запятой. Этот способ применяется в JavaScript для всех числовых значений без исключений, однако в других математических библиотеках, в которых он используется, кодирование может происходить с использованием совершенно других алгоритмов.
  2. Произвольная последовательность (строка) символов латинского алфавита, цифр и элементов пунктуации (от нуля и символов юникод). Каждая последующая строка отделяется от предыдущей строки посредством парного знака препинания — кавычек («текст») либо с использованием символа, с написанием, обратным по отношению к обычному символу, косой черты.
  3. Литералы или константы, включаемые непосредственно в текст. Это может быть любое значение из true и false или их аналогов.
  4. Массив. Он представляет собой упорядоченный перечень символов от нуля и дальше. Каждый символ может быть представлен в любой форме.
  5. Объект. Это хаотично сложенный состав пар ключи/значение. Исходя из того, что основная функция объектов состоит в представлении абстрактного типа данных, рекомендуется (но это необязательное условие), чтобы ключи были уникальными.
  6. Пустое значение, обозначающееся словом «Null».

Интервалы между символами допускаются, если они будут использованы между синтаксическими единицами. Для этого применяются несколько символов: обычное отступление, горизонтальные текстовые вкладки и косая черта.

Чем открыть формат JSON

Текстовый формат обмена данными может быть представлен в популярных стандартах кодирования, которые дают возможность более компактно хранить и пересылать символы Unicode. В частности, по умолчанию здесь стоит UTF-8. Также могут применяться UTF-16 и UTF-32. Их использование обуславливается тем, что все три стандарта поддерживают весь набор символов.

Но, если они экранированы (не цитирование), чтобы использовать их как регулярное выражение, они могут быть написаны для представления символов в дополнительных плоскостях с применением UTF-16.

Самый простой способ открыть формат JSON — использовать Блокнот на ПК.

Для этого необходимо создать и открыть новый текстовый документ, выбрать в левом верхнем углу «Файл», затем «Открыть».

Далее откроется окно проводника, посредством которого необходимо найти на ПК нужный файл, после чего нажать на кнопку «Все файлы».

Найдя нужный документ, следует нажать на кнопку проводника «Открыть».

Документ откроется и будет доступен для просмотра и редактирования.

Чтение и запись JSON в файл на Python

Запись JSON в файл на Python

Сериализация JSON относится к преобразованию данных в последовательность байтов (следовательно, последовательных) для хранения или передачи по сети. Для обработки потока данных в файле библиотека JSON в Python использует функцию dump () или dumps() для преобразования объектов Python в соответствующие объекты JSON, что упрощает запись данных в файлы. Смотрите следующую таблицу, приведенную ниже.

ОБЪЕКТ PYTHONОБЪЕКТ JSON
Диктобъект
список, кортежмассив
strстрока
int, long, floatчисла
Верноверно
Ложьложь
Нетnull

Способ 1. запись JSON в файл на Python с использованием json.dumps() 

Пакет JSON в Python имеет функцию под названием json.dumps(), которая помогает преобразовать словарь в объект JSON. Для этого требуется два параметра:

  • dictionary – имя словаря, который должен быть преобразован в объект JSON.
  • отступ – определяет количество единиц для отступа

После преобразования словаря в объект JSON просто запишите его в файл, используя функцию “write”.

import json

# Data to be written
dictionary = {
	"name": "sathiyajith",
	"rollno": 56,
	"cgpa": 8.6,
	"phonenumber": "9976770500"
}

# Serializing json
json_object = json.dumps(dictionary, indent=4)

# Writing to sample.json
with open("sample.json", "w") as outfile:
	outfile.write(json_object)

Вывод:

Способ 2. запись JSON в файл на Python с использованием json.dump() 

Другим способом записи JSON в файл является использование метода json.dump() Пакет JSON имеет функцию “dump”, которая напрямую записывает словарь в файл в форме JSON, без необходимости конвертировать его в фактический объект JSON. Он принимает 2 параметра:

  • dictionary – имя словаря, который должен быть преобразован в объект JSON.
  • указатель на файл – указатель на файл, открытый в режиме записи или добавления.

# Python program to write JSON
# to a file


import json

# Data to be written
dictionary = {
	"name": "sathiyajith",
	"rollno": 56,
	"cgpa": 8.6,
	"phonenumber": "9976770500"
}

with open("sample.json", "w") as outfile:
	json.dump(dictionary, outfile)

Вывод:

Чтение JSON из файла с использованием Python

Десериализация является противоположностью сериализации, то есть преобразования объектов JSON в соответствующие объекты Python. Для этого используется метод load(). Если вы использовали данные JSON из другой программы или получили их в строковом формате JSON, то их можно легко десериализовать с помощью load() , который обычно используется для загрузки из строки, в противном случае корневой объект находится в списке или Dict .

Чтение JSON из файла с помощью json.load() 

Пакет JSON имеет функцию json.load(), которая загружает содержимое JSON из файла JSON в словарь. Он принимает один параметр:

  • Указатель на файл: указатель на файл, который указывает на файл JSON.

import json

# Opening JSON file
with open('sample.json', 'r') as openfile:

	# Reading from json file
	json_object = json.load(openfile)

print(json_object)
print(type(json_object))

Вывод:

JSON в Python (подробнее)

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

К счастью, это достаточно тривиальная задача, и как и с большинством тривиальных задач, Python делает все до омерзения простым.

Итак, используем ли мы JSON для хранения и обмена данными? Именно так. Это не более, чем стандартизированный формат, который используется сообществом для передачи данных. Помните, что JSON не является единственным доступным форматом для такой работы, XML и YAML наверное, единственные альтернативные способы, которые стоит упомянуть.

Подробнее про JSON

Не удивительно, что JavaScript Object Notation был вдохновен подмножеством языка программирования JavaScript, связанным с синтаксисом объектного литерала. У них есть отличный сайт, в котором все прекрасно объясняется. Не переживайте: JSON уже давно стал агностиком языка и существует как отдельный стандарт, по этому мы можем убрать JavaScript из этой дискуссии.

В конечном счете, большая часть сообщества приняла JSON благодаря его простоте как для людей, так и для машин.
Смотрите, это JSON!

Структура JSON

Готовьтесь. Я собираюсь показать реальный пример JSON— такой же, какой вы встретите в реальной жизни. Это нормально, подразумевается что JSON является читаемым для любого, кто пользовался С-языками, а Python – это С-язык, так что мы говорим о вас!

{
    "firstName": "Jane",
    "lastName": "Doe",
    "hobbies": ["running", "sky diving", "singing"],
    "age": 35,
    "children": [
        {
            "firstName": "Alice",
            "age": 6
        },
        {
            "firstName": "Bob",
            "age": 8
        }
    ]
}

Как видите, JSON поддерживает примитивные типы, такие как строки python и числа, а также вложенные списки и объекты.

Погодите, это выглядит как словарь Python, верно? На данный момент это достаточно универсальная нотация объектов, и не думаю что UON может так же легко отскакивать от зубов. Кстати, предлагайте альтернативы в комментариях!

НУ что же, вы пережили первый контакт с диким JSON. Теперь вам нужно научиться приручать его!

Python поддерживает JSON

Python содержит встроенный модуль под названием json для кодирования и декодирования данных JSON.

Просто импортируйте модуль в начале вашего файла:

import json

Небольшой словарь

Как правило, процесс кодирования JSON называется сериализация. Этот термин обозначает трансформацию данных в серию байтов (следовательно, серийных) для хранения или передачи по сети. Также вы, возможно, уже слышали о термине «маршалинг», но это уже совсем другая область.

Естественно, десериализация — является противоположным процессом декодирования данных, которые хранятся или направлены в стандарт JSON.

Звучит как много технических терминов. Определенно. Но в реальности, все, о чем мы сейчас говорим — это чтение и написание. Представьте это следующим образом: кодирование это запись данных на диск, в то время как декодирование — это чтение данных в памяти.

Сериализация JSON

Что происходит после того, как компьютер обрабатывает большие объемы информации? Ему нужно принять дамп данных. Соответственно, модуль json предоставляет метод dump() для записи данных в файлы. Также есть метод dumps() для записей в строку Python.

Простые объекты Python переводятся в JSON согласно с весьма интуитивной конверсией.

PythonJSON
dictobject
list, tuplearray
strstring
int, long, floatnumber
Truetrue
Falsefalse
Nonenull

Пример сериализации JSON Python

Представьте, что вы работаете с объектом Python в памяти, который выглядит следующим образом:

data = {
    "president": {
        "name": "Zaphod Beeblebrox",
        "species": "Betelgeusian"
    }
}

Сохранить эту информацию на диск — критично, так что ваша задача — записать на файл.

Используя контекстный менеджер Python, вы можете создать файл под названием data_file.json и открыть его в режиме write (файлы JSON имеют расширение .json).

with open("data_file.json", "w") as write_file:
    json.dump(data, write_file)

Обратите внимание на то, что dump() принимает два позиционных аргумента: (1) объект данных, который сериализуется и (2), файловый объект, в который будут вписаны байты.

Или, если вы склонны продолжать использовать эти сериалзированные данные JSON в вашей программе, вы можете работать как со строкой.

json_string = json.dumps(data)

Обратите внимание, что файловый объект является пустым, так как вы на самом деле не выполняете запись на диск. Кроме того, dumps() аналогичен dump().

Ура! У вас получился малыш JSON и вы можете выпустить его в реальный мир, чтобы он вырос большим и сильным.

Несколько полезных аргументов

Помните, что JSON создан таким образом, чтобы быть читаемым для людей. Но читаемого синтаксиса недостаточно, если все слеплено вместе. Кроме этого, ваш стиль программирования скорее всего отличается от моего, и вам будет проще читать код, если он отформатирован по вашему вкусу.

Обратите внимание: Методы dump() и dumps() пользуются одними и теми же аргументами ключевых слов.

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

json.dumps(data)
json.dumps(data, indent=4)

Еще один вариант форматирования — это аргумент separators. По умолчанию, это двойной кортеж строк разделителя («, «, «: «), но обычно в качестве альтернативы для компактного JSON является («,», «:»). Взгляните на пример JSON еще раз, чтобы понять, где в игру вступают разделители.

Есть и другие аргументы, такие как sort_keys, но я не имею понятия, что он делает. Вы можете найти полный список в документации, если вам интересно.

Десериализация JSON

Отлично, похоже вам удалось поймать экземпляр дикого JSON! Теперь нам нужно предать ему форму. В модуле json вы найдете load() и loads() для превращения кодированных данных JSON в объекты Python.

Как и сериализация, есть простая таблица конверсии для десериализации, так что вы можете иметь представление о том, как все выглядит.

JSONPython
objectdict
arraylist
stringstr
number (int)int
number (real)float
trueTrue
falseFalse
nullNone

Технически, эта конверсия не является идеальной инверсией таблицы сериализации. По сути, это значит что если вы кодируете объект сейчас, а затем декодируете его в будущем, вы можете не получить тот же объект назад. Я представляю это как своего рода телепортацию: мои молекулы распадаются в точке А и собираются в точке Б. Буду ли я тем же самым человеком?

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

blackjack_hand = (8, "Q")
encoded_hand = json.dumps(blackjack_hand)
decoded_hand = json.loads(encoded_hand)

print(blackjack_hand == decoded_hand) # False

print(type(blackjack_hand)) # <class 'tuple'>
print(type(decoded_hand)) # <class 'list'>

print(blackjack_hand == tuple(decoded_hand)) # True

Пример десериализации JSON Python

На этот раз, представьте что у вас есть некие данные, хранящиеся на диске, которыми вы хотите манипулировать в памяти. Вам все еще нужно будет воспользоваться контекстным менеджером, но на этот раз, вам нужно будет открыть существующий data_file.json в режиме для чтения.

with open("data_file.json", "r") as read_file:
    data = json.load(read_file)

Здесь все достаточно прямолинейно, но помните, что результат этого метода может вернуть любые доступные типы данных из таблицы конверсий. Это важно только в том случае, если вы загружаете данные, которые вы ранее не видели. В большинстве случаев, корневым объектом будет dict или list.

Если вы внесли данные JSON из другой программы, или полученную каким-либо другим способом строку JSON форматированных данных в Python, вы можете легко десериализировать это при помощи loads(), который естественно загружается из строки:

json_string = """
{
    "researcher": {
        "name": "Ford Prefect",
        "species": "Betelgeusian",
        "relatives": [
            {
                "name": "Zaphod Beeblebrox",
                "species": "Betelgeusian"
            }
        ]
    }
}
"""

data = json.loads(json_string)

Ву а ля! Вам удалось укротить дикого JSON, теперь он под вашим контролем. Но что вы будете делать с этой силой — остается за вами. Вы можете кормить его, выращивать, и даже научить новым приемам. Не то чтобы я не доверяю вам, но держите его на привязи, хорошо?

Пример работы с JSON Python

Для тестового API, мы воспользуемся JSONPlaceholder, отличный источник фейковых данных JSON для практических целей.

Для начала, создайте файл под названием scratch.py, или как вам удобно. Здесь я не могу вас контролировать.

Вам нужно выполнить запрос API в сервис JSONPlaceholder, так что просто используйте пакет requests, чтобы он сделал за вас всю грязную работу. Добавьте следующие импорты вверху файла:

import json
import requests

Теперь вам предстоит поработать со списком TODOs, потому что… это своего рода обряд посвящения, вроде того.

Идем дальше и создаем запрос в API JSONPlaceholder для конечной точки GET /todos. Если вы слабо знакомы с запросами, есть очень удобный метод json(), который выполнит за вас всю работу, но вы можете попрактиковаться в использовании модуля json для десериализации атрибута текста объекта response. Это должно выглядеть следующим образом:

import json
import requests

response = requests.get("https://jsonplaceholder.typicode.com/todos")
todos = json.loads(response.text)

Не верится, что это работает? Хорошо, запустите файл в интерактивном режиме и проверьте лично. Пока вы там, проверьте тип todos. Если вам любопытно, обратите внимание на первые 10 элементов в списке.

import json
import requests
response = requests.get("https://jsonplaceholder.typicode.com/todos")
todos = json.loads(response.text)

print(todos == response.json()) # True
print(type(todos)) # <class 'list'>

print(todos[:10]) # ...

Как видите, никто вас не обманывает, и мы ценим здравый скептицизм.

Что такое интерактивный режим? Я уже думал вы не спросите! Вы знакомы с тем, что приходится постоянно прыгать туда-сюда между вашим редактором и терминалом? Мы, хитрые питонисты, используем интерактивный флаг -i, когда запускаем скрипт. Это отличный небольшой трюк для тестирования кода, так как он запускает скрипт, и затем открывает интерактивную командную строку с доступом ко всем данным скрипта!

Хорошо, теперь перейдем к действиям. Вы можете видеть структуру данных полученную от тестового API, посетив адрес в браузере https://jsonplaceholder.typicode.com/todos:

{
    "userId": 1,
    "id": 1,
    "title": "delectus aut autem",
    "completed": false
}

Здесь несколько пользователей, каждый из которых имеет уникальный userId, а каждая задача имеет свойство Boolean. Можете определить, какие пользователи выполнили большую часть задач?

import json
import requests

response = requests.get("https://jsonplaceholder.typicode.com/todos")
todos = json.loads(response.text)

# Соотношение userId с числом выполненных пользователем задач.
todos_by_user = {}

# Увеличение выполненных задач каждым пользователем.
for todo in todos:
    if todo["completed"]:
        try:
            # Увеличение количества существующих пользователей.
            todos_by_user[todo["userId"]] += 1
        except KeyError:
            # Новый пользователь, ставим кол-во 1.
            todos_by_user[todo["userId"]] = 1

# Создание отсортированного списка пар (userId, num_complete).
top_users = sorted(todos_by_user.items(), 
                   key=lambda x: x[1], reverse=True)

#Получение максимального количества выполненных задач.
max_complete = top_users[0][1]

# Создание списка всех пользователей, которые выполнили
# максимальное количество задач.
users = []
for user, num_complete in top_users:
    if num_complete < max_complete:
        break
    users.append(str(user))

max_users = " and ".join(users)

Да, да, ваша версия лучше, но суть в том, что теперь вы можете манипулировать данными JSON как нормальным объектом Python!

Не знаю как вы, но я запустил скрипт в интерактивном режиме еще раз, и получил следующий результат:

s = "s" if len(users) > 1 else ""
print(f"user{s} {max_users} completed {max_complete} TODOs")
# users 5 and 10 completed 12 TODOs

Это круто, и все такое, но мы занимаемся изучением JSON. В качестве вашей последней задачи, вы создадите файл JSON, который содержит готовые задачи (TODO) для каждого пользователя, который выполнил максимальное количество задач. Здесь мы использовали F-Строки Python.

Все, что вам нужно сделать, это отфильтровать задачи и вписать итоговый список в файл. Ради оригинальности, вы можете назвать файл выдачи filtered_data_file.json. Существует много способов сделать это, вот один из них:

# Определить функцию для фильтра выполненных задач
# с пользователями с максимально выполненными задачами.
def keep(todo):
    is_complete = todo["completed"]
    has_max_count = todo["userId"] in users
    return is_complete and has_max_count

# Записать отфильтрованные задачи в файл
with open("filtered_data_file.json", "w") as data_file:
    filtered_todos = list(filter(keep, todos))
    json.dump(filtered_todos, data_file, indent=2)

Отлично, теперь вы избавились от всех данных, которые вам не нужны и сохранили необходимое для нового файла!

Запустите скрипт еще раз и проверьте filtered_data_file.json, чтобы убедиться в том, что все работает. Он будет в той же папке, что и scratch.py, когда вы запустите его.

Теперь, когда вы зашли так далеко, вы начинаете понимать что коснулись темы с большим потенциалом, не так ли? Не зазнавайтесь: скромность сестра таланта. Хотя и не могу не согласиться. Пока что мы работали в плавном потоке, но под конец мы можем поддать газку.

Кодирование и декодирование объектов Python

Что случается, когда мы пытаемся сериализировать класс Elf из приложения Dungeons & Dragons, с которым вы работаете?

class Elf:
    def __init__(self, level, ability_scores=None):
        self.level = level
        self.ability_scores = {
            "str": 11, "dex": 12, "con": 10,
            "int": 16, "wis": 14, "cha": 13
        } if ability_scores is None else ability_scores
        self.hp = 10 + self.ability_scores["con"]

Ничего удивительного, Возникла ошибка, что класс Elf нельзя сериализировать:

elf = Elf(level=4)
json.dumps(elf)
TypeError: Object of type 'Elf' is not JSON serializable

Хотя, модуль json может обрабатывать большинство типов Python, он не понимает, как кодировать пользовательские типы данных по умолчанию. Это как пытаться поместить кубик в круглое отверстие — вам понадобится бензопила и надзор специалиста.

Упрощение структур данных

Сейчас вопрос в том, что делать с более сложными структурами данных. Например, вы можете попробовать кодировать и декодировать JSON вручную, но есть более разумное решение, которое избавит вас от лишней работы. Вместо того, чтобы идти непосредственно от пользовательского типа данных к JSON, вы можете перейти к промежуточному шагу.

Все что вам нужно, это отобразить ваши данные в контексте встроенных типов, которые изначально понятны json. По сути, вы переводите более сложный объект в его упрощенное представление, которое модуль json затем переводит в JSON.

Это наглядно представляется в математике: А = В, и В = С, значит А = С.

Чтобы добиться этого, вам нужен сложный объект для работы. Вы можете использовать любой пользовательский класс на ваш вкус, но Python имеет встроенный тип под названием complex, для представления сложных чисел, и он не может быть сериализированным по умолчанию. Итак, ради этих примеров, ваш сложный объект станет сложным объектом. Уже запутались?

z = 3 + 8j
print(type(z)) # <class 'complex'>

json.dumps(z)
TypeError: Object of type 'complex' is not JSON serializable

Откуда приходят комплексные числа? Когда реальное число и представляемое число очень любят друг друга, они складываются вместе для создания числа, которое (справедливо) называется комплексным.

Хороший вопрос, который стоит задать себе при работе со сложными типами: «Какой минимальный объем информации необходим для воссоздания этого объекта?» В случае со комплексными числами, вам нужно знать только реальное и представляемое число, доступ к которым (в качестве атрибутов) доступен в объекте complex:

z = 3 + 8j

print(z.real) # 3.0
print(z.imag) # 8.0

Передачи одних и тех же чисел в сложный конструктор достаточно для удовлетворения оператора сравнения __eq__:

z = 3 + 8j

print( complex(3, 8) == z ) # True

Разбивать пользовательские типы данных на их составляющие компоненты — критически важно как для процесса сериализации, так и для десериализации.

Кодирование пользовательских типов

Для перевода пользовательского объекта в JSON, все что вам нужно — это предоставить функцию кодирования параметру по умолчанию метода dump(). Модуль json вызовет эту функцию для любых объектов, которые не являются естественно сериализируемыми. Вот простая функция декодирования, которую вы можете использовать на практике:

def encode_complex(z):
    if isinstance(z, complex):
        return (z.real, z.imag)
    else:
        type_name = z.__class__.__name__
        raise TypeError(f"Object of type '{type_name}' is not JSON serializable")

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

>>> json.dumps(9 + 5j, default=encode_complex)
'[9.0, 5.0]'

>>> json.dumps(elf, default=encode_complex)
TypeError: Object of type 'Elf' is not JSON serializable

Почему мы кодируем комплексное число как кортеж? Хороший вопрос. Это определенно не является единственными выбором, впрочем, как и не является лучшим выбором. Фактически, это не может быть хорошим отображением, если вы планируете декодировать объект в будущем, что вы и увидите дальше.

Еще один частый подход — создать дочерний класс JSONEncoder и переопределить его метод default():

class ComplexEncoder(json.JSONEncoder):
    def default(self, z):
        if isinstance(z, complex):
            return (z.real, z.imag)
        else:
            super().default(self, z)

Вместо создания ошибки TypeError, вы можете дать классу base справиться с ней. Вы можете использовать его как напрямую в метод dump() при помощи параметра cls, или создав экземпляр encoder-а и вызова метода encode():

>>> json.dumps(2 + 5j, cls=ComplexEncoder)
'[2.0, 5.0]'

>>> encoder = ComplexEncoder()
>>> encoder.encode(3 + 6j)
'[3.0, 6.0]'

Декодирование пользовательских типов

В то время, как реальные и представляемые части сложных чисел абсолютно необходимы, на самом деле их не совсем достаточно для воссоздания объекта. Вот что случается, если вы попробуете кодировать комплексное число при помощи ComplexEncoder, а затем декодировать результат:

>>> complex_json = json.dumps(4 + 17j, cls=ComplexEncoder)
>>> json.loads(complex_json)
[4.0, 17.0]

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

Я предполагаю, что вопрос, который действительно важно задать себе, это «Какое минимальное количество информации, которая необходима, и которой достаточно для воссоздания объекта?»

Модуль json ожидает, что все пользовательские типы будут отображаться как объекты стандарта JSON. Для разнообразия, вы можете создать файл JSON, на этот раз назовем его complex_data.json и добавим следующий объект, отображающий комплексное число:

{
    "__complex__": true,
    "real": 42,
    "imag": 36
}

Заметили хитрую часть? Вот ключ «__complex__» является метаданными, которые мы только что упоминали. Неважно, какое ассоциируемое значение мы имеем. Чтобы эта хитрость сработала, все что вам нужно, это подтвердить существование ключа:

def decode_complex(dct):
    if "__complex__" in dct:
        return complex(dct["real"], dct["imag"])
    return dct

Если «__complex__» не находится в словаре, вы можете просто вернуть объект и позволить декодеру по умолчанию разобраться с этим.

Каждый раз, когда метод load() пытается парсить объект, у вас есть возможность выступить в роли посредника, перед тем как декодер пройдет свой путь с данными. Вы можете сделать это, спарсив вашу функцию декодирования с параметром object_hook.

Теперь сыграем в ту же игру, что и раньше:

with open("complex_data.json") as complex_data:
    data = complex_data.read()
    z = json.loads(data, object_hook=decode_complex)

print(type(z)) # <class 'complex'>

Хотя объект object_hook может показаться аналогом параметра по умолчанию метода dump(), на самом деле аналогия здесь же и заканчивается.

Это не просто работает с одним объектом. Попробуйте внести этот список сложных чисел в complex_data.json и запустить скрипт еще раз:

[
  {
    "__complex__":true,
    "real":42,
    "imag":36
  },
  {
    "__complex__":true,
    "real":64,
    "imag":11
  }
]

Если все идет гладко, вы получите список комплексных объектов:

with open("complex_data.json") as complex_data:
    data = complex_data.read()
    numbers = json.loads(data, object_hook=decode_complex)


print(numbers) # [(42+36j), (64+11j)]

Итоги

Поздравляю, теперь вы обладаете могущественной силой JSON для любых ваших потребностей в Python.

Хотя примеры, с которыми вы работали, безусловно, оригинальные и чрезмерно упрощены, они демонстрируют рабочий процесс, который вы можете применить к более общим задачам:

  1. Импорт модуля json
  2. Чтение данных с load() или loads()
  3. Обработка данных
  4. Запись измененных данных при помощи dump() или dumps()

Что вы будете делать с данными, после того как они загрузились в память — зависит от вашего случая. В целом, ваша задача — собрать данные из источника, извлечение полезной информации, и передача этой информации (или ее запись).

Сегодня вы проделали небольшое путешествие: вы поймали и приручили JSON, и вернулись домой как раз к ужину! И в качестве бонуса, научившись работать с модулем json, можете начать изучение модулей pickle и marshal.

Ссылка на статью

В самом json файле вместо букв непонятные символы

Ссылка

json поддерживает все возможные Юникодные символы, включая русские буквы.

И не нужно на print ориентироваться — это только запутает: чтобы правильно понять, что происходит, необходимо чётко представлять разницу между str(obj) и repr(obj), а также понимать разницу между строковыми константами в Питоне и json-строками — они могут выглядеть похоже, но это разные вещи.

>>> import json
>>> json.dumps(u"\N{EURO SIGN}")
'"\\u20ac"'
>>> s = u"\N{EURO SIGN}" # Строковая константа в Питоне
>>> print(s)
€
>>> print repr(s) # repr() это как строка в исходном коде может выглядеть
u'\u20ac'
>>> s # по умолчанию REPL использует repr()
u'\u20ac'
>>> repr(s) # представление представления repr(repr(s))
"u'\\u20ac'"
>>> s == u'\u20ac'
True
>>> data = json.dumps(s)
>>> data # json-текст 
'"\\u20ac"' # <- слэш в строковом объекте
>>> json.dumps(s, ensure_ascii=False)
u'"\u20ac"' # *нет* слэша в строковом объекте
>>> print(json.dumps(s, ensure_ascii=False))
"€"         # отсутствие слэша более очевидно
>>> json.loads(data)
u'\u20ac'
>>> print(json.loads(data))
€

Как удалить элемент из .json файла?

Удалить через del

data = [
{
"user_id": 1,
"first_name": "Elova",
"last_name": "Elizaveta"
},
{
"user_id": 2,
"first_name": "Alex",
"last_name": "Petrov"
}
]

print(data)

del data[1] # не забываем что это индекс

print(data)

Статья: КАК ЧИТАТЬ JSON-ФАЙЛ В PYTHON?

Привет всем! Сегодня мы попробуем разобраться: что такое JSON и как читать JSON-файл в Python?

Для начала — немного фактов:

  • JSON расшифровывается как JavaScript Object Notation
  • Это формат обмена данными, в котором вы можете передавать данные с клиента на сервер и с сервера на клиент
  • Он также используется для связи между приложениями
  • JSON чрезвычайно важен для разработки приложений, особенно когда вы работаете с API Rest
  • Он основан на подмножестве Java Script
  • Это легко читать и писать

С теорией познакомились, а теперь узнаем основные правила синтаксиса при работе с JSON-форматом:

  • JSON использует пары ключ-значение — {«name»: «Вася»}
  • JSON использует двойные кавычки вокруг ключа

Обычно в обучалках рассказывают о коллективе с данными по зарплате, месту проживания и все такое прочее. Не будем нарушать традицию, и представим себе коллектив, состоящий из 5 сотрудников: Вася, Саша, Петя, Даша, Маша. Каждый сотрудник получает определенную зарплату, а значит — мы можем составить свой JSON-файл (назовем файл personal.json), который и будет представлять собой список сотрудников + их зарплату:

{
"personal" :   [
{
"name" :   "Вася" ,
"salary" :   5000
} ,
 
{
"name" :   "Саша" ,
"salary" :   6000
} ,
 
{
"name" :   "Петя" ,
"salary" :   9000
 
} ,
 
{
"name" :   "Даша" ,
"salary" :   10000
 
},
 
{
"name" :   "Маша" ,
"salary" :   11000
 
}
]
}

как видно — поле name — отвечает за имя сотрудника, а поле salary — за уровень зарплаты, а вот само название этого массива данных — personal (указывается в самом верху). Файл с данными у нас есть, но как его читать? Для этого посмотрим на код ниже:

import json #Подключаем библиотеку, отвечающую за работу с JSON

with open('personal.json', 'r', encoding='utf-8') as f: #открываем файл personal.json и указываем его кодировку — что бы можно было работать с русскими буквами
    text = json.load(f) #загоняем в переменную все, что получилось в результате работы библиотеки
print(text) #выводим результат на экран

Если вы запустите код — то получите на экране нечто вроде:
{‘personal’: [{‘name’: ‘Вася’, ‘salary’: 5000}, {‘name’: ‘Саша’, ‘salary’: 6000}, {‘name’: ‘Петя’, ‘salary’: 9000}, {‘name’: ‘Даша’, ‘salary’: 10000}, {‘name’: ‘Маша’, ‘salary’: 11000}]}

Согласитесь — читать и разбирать подобные данные крайне сложно. Для упрощения работы в подобном случае часто используют библиотеку pprint, которая окультуривает выдачу в подобных случаях. В этом случае наш код будет выглядеть так:

import json #подключили библиотеку для работы с json
from pprint import pprint #подключили Pprint для красоты выдачи текста
 
with open('personal.json', 'r', encoding='utf-8') as f: #открыли файл с данными
    text = json.load(f) #загнали все, что получилось в переменную
    pprint(text) #вывели результат на экран

В результате выдача выглядит следующим образом:

  1. {‘personal’: [{‘name’: ‘Вася’, ‘salary’: 5000},
  2. {‘name’: ‘Саша’, ‘salary’: 6000},
  3. {‘name’: ‘Петя’, ‘salary’: 9000},
  4. {‘name’: ‘Даша’, ‘salary’: 10000},
  5. {‘name’: ‘Маша’, ‘salary’: 11000}]}

А теперь выведем данные в чистом виде — имя сотрудника + зарплата. Тогда код буде выглядеть так:

import json #Подключили библиотеку
 
with open('personal.json', 'r', encoding='utf-8') as f: #открыли файл
    text = json.load(f) #загнали все из файла в переменную
    print(text) #вывели результат на экран
 
for txt in text['personal']: #создали цикл, который будет работать построчно
    print(txt['name'], ':', txt['salary']) #и выводим на экран все, что в значении ключей name и salary

Собственно … можно было бы сказать что все, на сегодня хватит, но в завершении расскажу о том, как читать не файлы json, а строки.

Например, у нас будет json-строка:
stroke = ‘{«food»: «banana»}’
Если мы попробуем вывести ее на экран, то получим:
{«food»: «banana»} — что в целом доносит суть, но не соответствует правилам 🙂 Для вывода json-строки используется функция loads. В виде кода это выглядит следующим образом:

import json #подключаем библиотеку для работы с json
stroke = '{"food": "banana"}' #json-строка
stroke_s = json.loads(stroke) #загоняем в переменную результат чтения json-строки
print(stroke_s) #выводим результат на экран

На этом — все 🙂 Спасибо за внимание! И да — как записывать в json-файл мы разберемся смотрите ниже:

КАК СДЕЛАТЬ ДОБАВЛЕНИЕ ЗАПИСИ В JSON-ФАЙЛ В PYTHON?

Привет всем! Выше, мы разбирались, как читать json-файл. Пришла пора узнать, как сделать добавление записи в json-файл в Python. Поехали!

Как вы помните — в качестве примера у нас используется файл, в котором указаны имена сотрудников и размер их заработной платы. Выглядит сам файл следующим образом:
{
«personal»: [
{
«name»: «Вася»,
«salary»: 5000
},
{
«name»: «Саша»,
«salary»: 6000
},
{
«name»: «Петя»,
«salary»: 9000
},
{
«name»: «Даша»,
«salary»: 10000
},
{
«name»: «Маша»,
«salary»: 11000
}
]
}
и называется он personal.json. Как читать этот файл описано тут, повторяться не буду. Теперь о добавлении данных в файл. Делается это просто:

import json #Подключили библиотеку
new_data = {'name': 'Федот', 'salary': '15000'} #создали переменную, включающую в себя данные, которые мы хотим добавить в уже имеющийся файл
with open('personal.json', encoding='utf8') as f: #Открываем файл
    data = json.load(f) #Получае все данные из файла (вообще все, да)
    data['personal'].append(new_data) #Добавляем данные
with open('personal.json', 'w', encoding='utf8') as outfile: #Открываем файл для записи
    json.dump(data, outfile, ensure_ascii=False, indent=2) #Добавляем данные (все, что было ДО добавления данных + добавленные данные)

Можем проверить добавленное в файл:

import json #подключили библиотеку для работы с json
from pprint import pprint #подключили Pprint для красоты выдачи текста
 
with open('personal.json', 'r', encoding='utf-8') as f: #открыли файл с данными
    text = json.load(f) #загнали все, что получилось в переменную
    pprint(text) #вывели результат на экран

Видим, что после работы кода файл с данным выглядит следующим образом:

{
“personal”: [
{
“name”: “Вася”,
“salary”: 5000
},
{
“name”: “Саша”,
“salary”: 6000
},
{
“name”: “Петя”,
“salary”: 9000
},
{
“name”: “Даша”,
“salary”: 10000
},
{
“name”: “Маша”,
“salary”: 11000
},
{
“name”: “Федот”,
“salary”: “15000”
}
]
}

КАК УДАЛИТЬ ЗАПИСЬ ИЗ JSON-ФАЙЛА В PYTHON?

Привет всем! Давно (очень давно) я написал вот этот пост, посвященный добавлению данных в json-файл. Потом сделал видео по этому поводу, и вот вчера к видео был добавлен комментарий-просьба — сделать видео, посвященное вопросу: как удалить запись из json-файла в Python? Видео — добавлю совсем скоро, а вот текст и код — ниже. Поехали!

Итак, как добавлять записи в json-файл мы знаем. А вот как удалить ту или иную запись по ключу (мы же помним, что в целом json — это тот же словарь, а значит имеет связку «Ключ-значение»)? На самом деле — все просто. Итак, у нас имеется json-файл с данными о зарплате пользователей. Как выглядит этот файл можно увидеть выше:

Теперь напишем код, который будет в качестве входного параметра получать имя пользователя, данные о котором нам нужно удалить (фактически — это ключ), а после — если искомый ключ (имя пользователя) — будут найдены — удалять эти записи.

Выглядит код следующим образом:

import json
 
user_for_del = str(input('Введите имя сотрудника, данные о котором нужно удалить? \n'))
with open('personal.json', 'r', encoding='utf-8') as f:
    data = json.load(f)
    minimal = 0
for txt in data['personal']:
    if txt['name'] == user_for_del:
        data['personal'].pop(minimal)
    else:
        None
    minimal = minimal + 1
with open('personal.json', 'w', encoding='utf-8') as outfile:
    json.dump(data, outfile, ensure_ascii=False, indent=2)

Введём Саша, проверим, наличие Саши.

import json #подключили библиотеку для работы с json
from pprint import pprint #подключили Pprint для красоты выдачи текста
 
with open('personal.json', 'r', encoding='utf-8') as f: #открыли файл с данными
    text = json.load(f) #загнали все, что получилось в переменную
    pprint(text) #вывели результат на экран

Саши нет:

{'personal': [{'name': 'Вася', 'salary': 5000},
              {'name': 'Петя', 'salary': 9000},
              {'name': 'Даша', 'salary': 10000},
              {'name': 'Маша', 'salary': 11000},
              {'name': 'Федот', 'salary': '15000'}]}

В самом начале — подключаем библиотеку json, которая упрощает работу с json 🙂
После этого — получаем переменную, которая состоит из имени пользователя, которого мы будем удалять из нашего файла (фактически — это ключ в нашем словаре).
А теперь — открываем json-файл, и делаем из него словарь (в том, что это словарь — вы можете убедиться, если выведите тип переменной data). А теперь уже — совсем просто все — обрабатываем в цикле каждый элемент словаря, и сравниваем его с нашей переменной user_for_del (имя пользователя, которого мы будему удалять из json-файла): если значение совпадает — удаляем эту запись (именно для этого нам и нужна переменная minimal, которая, фактически, служит для создания номера записи). Удалили запись? Великолепно! А теперь конвертируем наш обработанный словарь в json-файл и сохраняем изменения 🙂

UPD: вот и видео подоспело…