Как пропустить ключи в словаре python при поиске значения

#python #python-3.x #amazon-web-services

Вопрос:

Я вызываю API ценообразования AWS, чтобы получить почасовую стоимость своих инстансов EC2, и это пример того, что я получаю за их цены по требованию:

 {"OnDemand": {
        "QA3NBPZEQKZ2K9AR.JRTCKXETXF": {
            "effectiveDate": "2021-08-01T00:00:00Z",
            "offerTermCode": "JRTCKXETXF",
            "priceDimensions": {
                "QA3NBPZEQKZ2K9AR.JRTCKXETXF.6YS6EN2CT7": {
                    "appliesTo": [],
                    "beginRange": "0",
                    "description": "$0.0208 per On Demand Linux t3.small Instance Hour",
                    "endRange": "Inf",
                    "pricePerUnit": {
                        "USD": "0.0208000000"
                    },
                    "rateCode": "QA3NBPZEQKZ2K9AR.JRTCKXETXF.6YS6EN2CT7",
                    "unit": "Hrs"
                }
            },
            "sku": "QA3NBPZEQKZ2K9AR",
            "termAttributes": {}
        }
    }
}
 

Моя цель-получить цену за единицу стоимости, и я мог бы легко сделать это, сделав что-то вроде:

 hourly_cost = price_list['OnDemand']['QA3NBPZEQKZ2K9AR.JRTCKXETXF']['priceDimensions']['QA3NBPZEQKZ2K9AR.JRTCKXETXF.6YS6EN2CT7']['pricePerUnit']['USD']
 

Однако ключи, такие как «QA3NBPZEQKZ2K9AR.JRTCKXETXF» и «QA3NBPZEQKZ2K9AR.JRTCKXETXF.6YS6EN2CT7», заполняются случайным образом для каждого экземпляра EC2, поэтому я не могу использовать эти два значения для извлечения данных для всех экземпляров.

Я ищу способ пропустить эти два ключа и получить скидку.

Комментарии:

1. Где ключ ['OnDemand'] ?

2. @It_is_Chris Есть ключ с именем «По требованию», значение которого соответствует приведенному выше словарю

3. Словарь должен быть {'OnDemand': {...}}

4. @It_is_Chris Я обновил код. Надеюсь, теперь в этом больше смысла. Как бы вы продолжили решать эту проблему?

Ответ №1:

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

 import re
d[re.compile('[w]*')]
 

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

Ответ №2:

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

 from collections import namedtuple
x = {"OnDemand": {
        "QA3NBPZEQKZ2K9AR.JRTCKXETXF": {
            "effectiveDate": "2021-08-01T00:00:00Z",
            "offerTermCode": "JRTCKXETXF",
            "priceDimensions": {
                "QA3NBPZEQKZ2K9AR.JRTCKXETXF.6YS6EN2CT7": {
                    "appliesTo": [],
                    "beginRange": "0",
                    "description": "$0.0208 per On Demand Linux t3.small Instance Hour",
                    "endRange": "Inf",
                    "pricePerUnit": {
                        "USD": "0.0208000000"
                    },
                    "rateCode": "QA3NBPZEQKZ2K9AR.JRTCKXETXF.6YS6EN2CT7",
                    "unit": "Hrs"
                }
            },
            "sku": "QA3NBPZEQKZ2K9AR",
            "termAttributes": {}
        }
    }
}

InstanceData = namedtuple('InstanceData', ['Instancekey','priceDimensions'])
InstancePriceDimensions = namedtuple(
                            'InstancePriceDimensions', 
                            ['InstanceKey', 'PriceDimensionKey','pricePerUnit']
                            )

InstanceDataCollection = []
InstancePriceCollection = []

for key, value in x["OnDemand"].items():
    InstanceDataCollection.append(InstanceData(key, value))
    for x, val in value["priceDimensions"].items():
        if "pricePerUnit" in val:
            InstancePriceCollection.append(
                InstancePriceDimensions(
                                key, 
                                x, 
                                val["pricePerUnit"]
                                )
                )
            
print(InstancePriceCollection)
for x in InstancePriceCollection:
    #aggregate the metric over whole collection or process them
    print(x.pricePerUnit['USD'])
 

Ответ №3:

Вы можете использовать dict.keys() предположение, что структура такая же

 k1 = list(d['OnDemand'].keys())[0]
k2 = list(d['OnDemand'][k1]['priceDimensions'].keys())[0]
d['OnDemand'][k1]['priceDimensions'][k2]['pricePerUnit']['USD']
 

Ответ №4:

Глядя на структуру ответа JSON, я думаю, что у вас есть несколько вариантов здесь.

Поскольку вложенные объекты с такими ключами QA3NBPZEQKZ2K9AR.JRTCKXETXF по сути являются оболочками вокруг другого подобъекта, вам не обязательно беспокоиться о поиске по списку объектов в поисках любого или всего pricePerUnit , вы можете просто получить доступ к списку значений и извлечь первое значение:

 # pulls the value associated with the key `QA3NBPZEQKZ2K9AR.JRTCKXETXF`
outer = list(price_list['OnDemand'].values())[0]

# pulls the value associated with the key `QA3NBPZEQKZ2K9AR.JRTCKXETXF.6YS6EN2CT7`
inner = list(outer["priceDimensions"].values())[0]

price_per_unit = inner["pricePerUnit"]
 

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

Ответ №5:

Вероятно, есть более краткий способ сделать это, и он зависит от структуры, которая в точности соответствует тому, что указано в вопросе, но она работает. Он отличается от ответа, данного ранее, тем, что позволяет использовать несколько ключей «тайны» в любом словаре OnDemand. Конечно, в этом может и не быть необходимости.

 D = {'OnDemand': {
    "QA3NBPZEQKZ2K9AR.JRTCKXETXF": {
        "effectiveDate": "2021-08-01T00:00:00Z",
        "offerTermCode": "JRTCKXETXF",
        "priceDimensions": {
            "QA3NBPZEQKZ2K9AR.JRTCKXETXF.6YS6EN2CT7": {
                "appliesTo": [],
                "beginRange": "0",
                "description": "$0.0208 per On Demand Linux t3.small Instance Hour",
                "endRange": "Inf",
                "pricePerUnit": {
                    "USD": "0.0208000000"
                },
                "rateCode": "QA3NBPZEQKZ2K9AR.JRTCKXETXF.6YS6EN2CT7",
                "unit": "Hrs"
            }
        },
        "sku": "QA3NBPZEQKZ2K9AR",
        "termAttributes": {}
    }
}
}

base = D['OnDemand']
for b in base.keys():
    pd = base[b]['priceDimensions']
    for d in pd.keys():
        print(pd[d]['pricePerUnit']['USD'])
 

Ответ №6:

Вы можете использовать dict.values() , чтобы игнорировать ключи:

 v = lambda d: list(d.values())[0]
hourly_cost = v(v(v(price_list))['priceDimensions'])['pricePerUnit']['USD']