#python #yaml
Вопрос:
У меня есть файл yaml, который я хотел бы повторить и сохранить все из списка как новую переменную с тем же именем.
- app1:
name: example1
host: example1
run: myscript1.sh
tags:
- "user"
- "age"
- "gender"
- app2:
name: example2
host: example4
tags:
- "user"
- "age"
- "height"
Код:
for i in range(0, len(data)):
for key, value in data[i].items():
print(value.get('tags'))
for n in tags:
print(n)
выход:
['user', 'age', 'gender']
user
age
user
['user', 'age', 'height']
user
age
height
Хотелось бы в новой итерации сохранить эти значения в качестве переменных,
user = 'user'
age = 'age'
height = 'height'
и в следующей итерации:
user = 'user'
age = 'age'
gender = 'gender'
Таким образом, я могу передать эти переменные некоторым другим элементам кода.
Редактировать
переменная yaml (например, хост) будет заполнена значениями из Elasticsearch. Если мы определим в тегах «возраст», я буду искать в Elasticsearch «возраст» и извлекать значение из документа, чтобы оно стало «возрастом»: «20». После этого этот тег «возраст» будет вызван в скрипте sh, что-то вроде:
for doc1 in resp['hits']['hits']:
command = f"{value.get('run')} --age {age} #and other tags"
p = subprocess.Popen(command.split(), shell=False, stdout=subprocess.PIPE)
Ответ №1:
Я не совсем уверен, чего вы хотите, но я думаю, что вам нужно что-то вроде этого:
# test.yml
- app1:
name: example1
host: example1
tags:
- "user"
- "age"
- "gender"
- app2:
name: example2
host: example4
tags:
- "user"
- "age"
- "height"
import yaml
from pathlib import Path
with Path("test.yml").open() as f:
data = yaml.load(f)
out = []
for entry in data:
app, *_ = entry.keys()
tags = {k: k for k in entry[app]["tags"]}
out.append(tags)
print(out)
Вместо этого вы можете легко сохранить их по названию приложения, оформив диктант.
Обратите внимание, что я не знаю, почему вам нужны избыточные пары ключ/значение, и если tags
на самом деле предполагается, что они содержат данные (в отличие от вашего примера), вам придется сделать что-то вроде:
tags = {k:v for k, v in entry[app]["tags"].items()}
Наконец, вы, конечно, можете вернуться в yaml с yaml.dump(out)
помощью .
** Распаковка
Мне приходит в голову, что вы, возможно, захотите распаковать этот диктант в функцию. Вы можете сделать это вот так:
def my_fn(user=None, age=None, gender=None, height=None):
print("user", user, "age", age, "gender", gender, "height", height)
out = [{'user': 'user', 'age': 'age', 'gender': 'gender'},
{'user': 'user', 'age': 'age', 'height': 'height'}]
for row in out:
my_fn(**row)
Таким образом, * * распаковывает диктант в аргументы ключевых слов, которые могут быть тем, что вы искали. (Во всяком случае, для меня это имеет больше смысла, чем генерирование переменных с программными именами). Обратите app, *_
внимание на то, что распаковано entry.keys()
, чтобы мы могли получить первый элемент без необходимости приводить его к индексируемому типу. dict.keys()
это не генератор, так что вы не можете им пользоваться next(dict.keys())
. Эта конкретная распаковка является недавним (и очень полезным) дополнением к python.
ИЗМЕНИТЬ: использование этих переменных
переменная yaml (например, хост) будет заполнена значениями из Elasticsearch. Если мы определим в тегах «возраст», я буду искать в Elasticsearch «возраст» и извлекать значение из документа, чтобы оно стало «возрастом»: «20».
Верно. Поэтому вы хотите посмотреть , в каких записях tags
содержатся данные, а затем заполнить их правильными значениями. Итак, вы хотите сделать что-то вроде этого:
for entry in data:
tags = {}
app, *_ = entry.keys()
for tag in in entry[app]["tags"]:
val = get_tag_value_from_elasticsearch(tag)
tags[tag] = val
После этого этот тег «возраст» будет вызван в скрипте sh
Так что—все еще в том же цикле для простоты, но вы всегда можете добавить tags
в список, а затем повторить этот список позже:
cmd = ["command"]
for param, val in tags.items():
cmd = [f"--{param}", str(val)]
res = subprocess.run(cmd, capture_output=True)
print(res.stdout)
Обратите внимание на несколько вещей здесь: я избегал использования .get()
для поиска значения в дикте, когда я могу просто использовать []
доступ; Я использовал subprocess.run
вместо Popen (если вы хотите создать фон, вам придется вернуться к Popen), и я создал команду непосредственно в списке, а не строил строку и разделял ее.
На данный момент все, что вы хотите с этим сделать, — это, я думаю, еще один вопрос, поэтому я оставлю этот ответ здесь.
Комментарии:
1. Привет, спасибо за ваши вводы, дело в том, что мне нужно это сделать, потому что на основе параметров, определенных в yaml, я выполняю поисковый запрос в elasticsearch, и мне нужно сохранить эти «конкретные» значения в качестве переменных. Например, я буду искать рост и пол, а затем сохраню эти 2 -> после этого мне нужно вызвать какой-нибудь скрипт sh с этими параметрами. Не уверен, что я ясно выразился, попытаюсь объяснить в следующем комментарии
2. Посмотрите, что я делаю в последней части (попробуйте запустить это). Я думаю, вы можете получить необходимые вам данные. Но это определенно помогло бы, если бы вы привели пример того, как вы хотите использовать эти данные в вопросе. Я сохраняю данные в переменной-в частности, в dict, которую затем можно распаковать в функцию при вызове.
3. Thnx @2e0byo , я внес правки, надеюсь, теперь вы понимаете, что я делал
4. Верно, я обновил этот ответ (но он настолько невеселый, что я собираюсь оставить его там). Надеюсь, это даст вам инструменты для ее решения 🙂
5. tnx, просто получаю ошибку имени: имя «get_tag_value_from_elasticsearch» не определено, я не уверен, что это такое