В поддержку новой инициативы Code Recipes. Искренне надеюсь на вашу помощь и всяческую поддержку в виде новых code recipes!
Если Вы программируете на Python, то знаете что словарь является очень важной структурой. И не только является важным для самого языка программирования, а и для автоматизации тестирования на этом языке. Ведь очень часто приходиться описывать данные в формате ключ: значение
. Такие данные могут быть большие по объему описываемых данных, а также не существовать в момент обращения к словарю . И если использовать стандартные механизмы словаря, то описать вложенные подсловари неудобно, а тем более если вы хотите создавать структуру данных программно в режиме runtime.
Пример, нам надо создать структуру:
{
"server": {
"host": "127.0.0.1",
"port": "22"
},
"configuration": {
"ssh": {
"access": "true",
"login": "some",
"password": "some"
}
}
}
Стандартный способ решения этой задачи
data = {}
# some logic here
print data["server"] # will raise exception due to 'KeyError: 'server''
# some logic here
data["server"] = {
"host": "127.0.0.1",
"port": "22"
}
# some logic here
if data["configuration"]["ssh"]["login"]: # will raise exception here
pass
# some logic here
data["configuration"] = {
"ssh": {
"access": "true",
"login": "some",
"password": "some"
}
}
Немного улучшенный вариант
У словаря можно использовать get метод, чтобы получить значение и не выдавать исключение и возвращать, дефолтное значение. Но если в случае с data["server"]
это сработает, то с data["configuration"]["ssh"]["login"]
не сработает, так как возвращаемый объект будет типа None
data = {}
# some logic here
print data.get("server")
# some logic here
data["server"] = {
"host": "127.0.0.1",
"port": "22"
}
# some logic here
if data.get("configuration").get("ssh").get("login"):
# will raise exception
# AttributeError: 'NoneType' object has no attribute 'get'
pass
# some logic here
data["configuration"] = {
"ssh": {
"access": "true",
"login": "some",
"password": "some"
}
}
Но если задать дефолтные значения для data.get("configuration").get("ssh").get("login")
чтобы не получать ошибку AttributeError: 'NoneType' object has no attribute 'get'
, то можно получить нормальный результат
data = {}
# some logic here
print data.get("server")
# some logic here
data["server"] = {
"host": "127.0.0.1",
"port": "22"
}
# some logic here
if data.get("configuration", {}).get("ssh", {}).get("login", {}):
# will raise exception
# AttributeError: 'NoneType' object has no attribute 'get'
pass
# some logic here
data["configuration"] = {
"ssh": {
"access": "true",
"login": "some",
"password": "some"
}
}
Готовый рецепт, усовершенствованный способ
А можно использовать возможности defaultdict
from collections import defaultdict
_default_data = lambda: defaultdict(_default_data)
data = _default_data()
# some logic here
print data["server"]
# some logic here
data["server"]["host"] = "127.0.0.1"
data["server"]["port"] = "22"
# some logic here
if data["configuration"]["ssh"]["login"]:
print ("some logic")
# some logic here
data["configuration"]["ssh"]["access"] = "true"
data["configuration"]["ssh"]["login"] = "some"
data["configuration"]["ssh"]["password"] = "some"
import json
print json.dumps(data, indent=2)
defaultdict(<function <lambda> at 0x02565930>, {})
{
"configuration": {
"ssh": {
"access": "true",
"login": "some",
"password": "some"
}
},
"server": {
"host": "127.0.0.1",
"port": "22"
}
}
Результат получается без всяких исключений и сложностей, и мы можем задавать любую структуру из подвложенных словарей без фактического определения самих объектов, а также получаем возможность проверки словаря без исключений и удобную стандартную форму записи словаря.
Все варианты кода можно посмотреть на нашей общем репозитории примеров at.info-knowledge-base/programming/python/code recipes/generate nested dicts at master · atinfo/at.info-knowledge-base · GitHub
Ну и кто хочет учиться python и автоматизации, милости прошу на http://lessons2.ru