Книга открытых ордеров на эксмо содержит занятную структуру данных:
{"BTC_USD":{"ask_quantity":"226.82420996","ask_amount":"2992323.79093759","ask_top":"8475","bid_quantity":"11720.48826229","bid_amount":"1243102.82950626","bid_top":"8453.490004","ask":[["8475","0.0591663","501.4343925"],["8480","0.00145227","12.3152496"],["8484.99","0.05216288","442.60151517"]],"bid":[["8453.490004","0.037","312.77913014"],["8453.390004","0.405","3423.62295162"],["8453.290002","0.00175728","14.85479745"]]}}
Если вы понимаете, о чем это всё – фигурные скобки, двоеточия, квадратные скобки, кавычки и т.п., то эта статья не для вас. Иначе – welcome aboard! К концу статьи такие вещи как книга ордеров будут щелкаться как орешки.
Роботы и рестораны
Знаете вы или нет, но роботы уже плотно ворвались в нашу жизнь. Например, в Сингапуре роботы заменяют официантов – принимают заказы от клиентов и развозят заказы по столикам и увозят грязную посуду.
Давайте пофантазируем и предположим, что владелец ресторана в Кондапоге решил привлечь внимание посетителей к своему заведению, закупил железо и теперь просит вас написать для них программное обеспечение. Почему он выбрал именно вас и почему вы будете писать код на Питоне, оставим за кадром. Поехали.
Итак, вам надо в удобном виде предоставить меню. В меню есть первые блюда, вторые, напитки, десерты, мороженное и т.п. У каждого блюда есть какая-то единица измерения и стоимость, у некоторых есть возможность выбора ингредиентов.
Как не надо:
Начинающий программист начнет с обычных переменных, и в них же утонет. Например, он может написать так:
borsch = 150
kvas = 100
подразумевая, что борщ продается по 150, а квас по 100. Но потом он вспомнит, что квас бывает в большом стакане и маленьком, и появится новый виток мысли:
borsch = 150
kvas_little = 70
kvas_big = 100
Потом внезапно окажется, что к борщу можно подать сметану, белый или черный хлеб. Появится новый набор:
borsch = 150
kvas_little = 70
kvas_big = 100
borsch_extra_1 = "Сметана"
borsch_extra_2 = "Белый хлеб"
borsch_extra_3 = "Черный хлеб"
Потом окажется, что надо на экране выводить список того, что есть в меню, и появится новый пассаж:
print("borsch="+borsch, "kvas_little="+kvas_little)
и т.п. В итоге такой робот выехал в зал, клиент посмотрел «меню» и сказал – я буду borsch со сметаной и kvas_big. Что бы передать заказ клиента на кухню, программисту придется писать что-то такое:
if "borsch":
print("Клиент заказал borsch за " + str(borsch) + " рублей")
if "kvas_little":
print("Клиент заказал kvas_little за " + str(kvas_little) + " рублей")
if "kvas_big":
print("Клиент заказал kvas_big за " + str(kvas_big) + " рублей")
и т.п.
В итоге, когда владелец ресторана решит убрать из меню квас и добавить лимонад, а также 50 видов пиццы, программист повесится.
Как надо.
Для того, чтобы удобно хранить разнородные статичные данные и получать к ним доступ во многих языках разработаны словари (они же хеш-таблицы, они же ассоциативные массивы). Словарь – это, хм, словарь. Например, англо-русский словарь содержит слова на английском (ключи), которым соответствуют значения на русском. Любой словарь, это связка ключа и значения.
В питоне пустой словарь создается и обозначается так: {}
например
menu = {}
Ключи и значения обозначаются через двоеточие, например, если бы мы хотели перенести код выше в словарь, мы могли бы написать так:
menu = {"borsch":150, "kvas":100}
и потом «вытащить» эти значения вот так:
print(menu["borsch"])
print(menu["kvas"])
но это пока что не добавляет изящности, поэтому мы сделаем красивее: мы в словарь вложим отдельные словари. Любой ключ может ссылаться как на значение, так и на другой словарь, массив, экземпляр класса и т.п. Более красивая структура могла бы иметь такой вид:
menu = {
"borsch": {
"price":150,
"name": "Борщ",
"extra": ["Сметана", "Белый хлеб", "Черный хлеб"]
},
"kvas": {
"name": "Квас",
"little": {
"price": 70,
"amount": 0.3
},
"big": {
"price": 100,
"amount": 0.5
}
}
}
Сделаем print(menu) и посмотрим, что возвращается:
{'borsch': {'price': 150, 'name': 'Борщ', 'extra': ['Сметана', 'Белый хлеб', 'Черный хлеб']}, 'kvas': {'name': 'Квас', 'little': {'price': 70, 'amount': 0.3}, 'big': {'price': 100, 'amount': 0.5}}}
Уже похоже на ответ exmo, правда?
Теперь, когда клиент спросит «А что у вас есть?», робот может выполнить что то такое (что бы получить ключи массива):
for item in menu:
print(item)
borsch
kvas
Или вот так:
print(menu.keys())
Но зачем клиенту знать внутренние обозначения? Надо писать по русски. Например, так:
for item in menu:
print(menu[item]['name'])
Что произошло?
Когда мы пишем for item in menu, питон берет словарь, и, до тех пор, пока в словаре есть ключи, получает следующий ключ и присваивает его переменной item (или как вы её назовете). Разберем подробнее:
menu = {
"borsch": {
"price":150,
"name": "Борщ",
"extra": ["Сметана", "Белый хлеб", "Черный хлеб"]
},
"kvas": {
"name": "Квас",
"little": {
"price": 70,
"amount": 0.3
},
"big": {
"price": 100,
"amount": 0.5
}
}
}
for any_variable_name in menu:
print("Текущее значение переменной any_variable_name=", any_variable_name)
print("В словаре под этим ключом хранится вот что: ", menu[any_variable_name])
print("Возьмем из вложенного словаря значение name -> ", menu[any_variable_name]['name'])
print('---')
Похожих результатов можно добиться, если использовать метод словаря items(). Этот метод возвращает сразу и ключ, и значение. Заменим код на вот такой, что бы код был проще и «чище»:
menu = {
"borsch": {
"price":150,
"name": "Борщ",
"extra": ["Сметана", "Белый хлеб", "Черный хлеб"]
},
"kvas": {
"name": "Квас",
"little": {
"price": 70,
"amount": 0.3
},
"big": {
"price": 100,
"amount": 0.5
}
}
}
for key, value in menu.items():
print(key, value)
print(value['name'])
print('---')
Но бывает такое, что мы не знаем, есть ключ в словаре или нет – например, у борща есть цена price, а у кваса нет. Есть несколько способов проверить – каждый подбирается по ситуации.
menu = {
"borsch": {
"price":150,
"name": "Борщ",
"extra": ["Сметана", "Белый хлеб", "Черный хлеб"]
},
"kvas": {
"name": "Квас",
"little": {
"price": 70,
"amount": 0.3
},
"big": {
"price": 100,
"amount": 0.5
}
}
}
for key, value in menu.items():
print("Вариант 1")
print(value['name'])
if 'price' in value:
print("Цена", value['price'])
print('---')
print("Вариант 2")
print(value['name'])
print("Цена", value.get('price', 'Не указано'))
print('---')
print("Вариант 3")
print(value['name'])
try:
print("Цена", value['price'])
except KeyError:
print("Цена не указана")
print('---')
print("Вылетит с ошибкой, если нет цены")
print("Цена", value['price'])
print('---')
В первом случае мы проверили, есть ли ключ, и, если есть, вывели значение.
Во втором, воспользовались методом get(), который либо выведет значение указанного ключа, либо выведет указанное нами значение.
В третьем случае, мы выводим цену в любом случае, но если её нет, то перехватываем ошибку, и пишем своё сообщение.
В четвертом случае выводим как есть, и, если ключа нет, вылетает ошибка (вообще-то такие «ошибки» называются исключениями, но об этом в другой раз).
Работа с элементами словаря
До этого мы руками завели словарь (или получили готовый), давайте посмотрим, как можно манипулировать содержимым.
menu = {
"borsch": {
"price":150,
"name": "Борщ",
"extra": ["Сметана", "Белый хлеб", "Черный хлеб"]
},
"kvas": {
"name": "Квас",
"little": {
"price": 70,
"amount": 0.3
},
"big": {
"price": 100,
"amount": 0.5
}
}
}
# Добавим вареники
menu["vareniki"] = {"price":20, 'name': "Вареники"}
print(menu)
# Удалим вареники
del menu['vareniki']
print(menu)
# Заменим квас на строку
menu['kvas'] = "Закончился"
print(menu)
# Добавим 50 сортов пиццы по 300 рублей
for i in range(100):
menu["pizza_"+str(i)] = {"price":300, 'name': "Пицца " + str(i)}
print(menu)
# Очистим словарь
menu.clear()
print(menu)
Что бы вам еще рассказать?
Узнать количество ключей словаря можно узнать с помощью len()
print(len(menu))
Иногда людям зачем-то хочется еще и сортировать словари в алфавитном или ином порядке. Вообще, это не задача для словарей, т.к. они спроектированы не для этого, а для того, что бы как можно быстрее возвращать значения для указанного ключа. Но если очень хочется, то можно воспользоваться такой конструкцией:
for k in sorted(menu):
print(k)
Что бы выводить в обратном порядке, добавьте параметр функции:
for k in sorted(menu, reverse=True):
print(k)
По сути сейчас словарь не отсортировался, а были получены ключи, которые и были отсортированы.
Заключение
Ну, и для закрепления давайте рассмотрим пример из начала статьи - тот же словарь, в нем другие словари, местами массивы.. Ну, вы сами знаете :)
exmo_response = {"BTC_USD":{"ask_quantity":"226.82420996","ask_amount":"2992323.79093759","ask_top":"8475","bid_quantity":"11720.48826229","bid_amount":"1243102.82950626","bid_top":"8453.490004","ask":[["8475","0.0591663","501.4343925"],["8480","0.00145227","12.3152496"],["8484.99","0.05216288","442.60151517"]],"bid":[["8453.490004","0.037","312.77913014"],["8453.390004","0.405","3423.62295162"],["8453.290002","0.00175728","14.85479745"]]}}
for pair, value in exmo_response.items():
print("Пара",pair)
print("Лучшие цены", value['ask_top'], value['bid_top'])
print("Стаканы:")
print("Продажа", value['ask'])
print("Покупка", value['bid'])
for item in value['ask']:
print("Готовы продать {amount:0.8f} по курсу {rate:0.8f}".format(
amount=float(item[1]), rate=float(item[0])
))
Всем удачи и позитива )