簡體   English   中英

訪問深度嵌套的 Python 字典的元素

[英]Accessing Elements of a Deeply Nested Python Dictionary

我正在嘗試訪問字典中鍵的嵌套元素,但每次嘗試遍歷它們時都會掛斷。

我試圖展平字典並嘗試對元素進行各種索引訪問器,但沒有運氣。

目標:訪問各個元素,例如:

print(flat['_items'][0]['items']['timestamp'])
print(flat['_items'][0]['items']['value'])

以下是我嘗試訪問的代碼、數據和元素。

def flatten_dict(dd, separator='_', prefix=''):
    return { prefix + separator + k if prefix else k : v
             for kk, vv in dd.items()
             for k, v in flatten_dict(vv, separator, kk).items()
             } if isinstance(dd, dict) else { prefix : dd }  

# Attempt to Flatten the Dictinary
flat = flatten_dict(regDataDict)

for k in flat.keys():
    print(k)   
    
for k, v in flat.items():
    print(k, v)

print(flat['_items'][0]['items']['timestamp']) # TypeError: string indices must be integers
print(flat['_items'][0]) # Prints all Dictionary Keys and Values
print(flat['_items']) # Prints all Dictionary Keys and Values
print(flat['_items']['{items}']) # TypeError: string indices must be integers

字典結構

_items = [
    {'items': [{'errors': None,
                'good': True,
                'questionable': False,
                'substituted': False,
                'timestamp': '2021-02-01T21:40:00Z',
                'value': -180.625427,
                'web_exception': None}],
     'links': {'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegw8PMMAA'},
     'web_id': 'I1DPOGpIXSBWLkGcEkjIvyMegw8PMMAA'},
    {'items': [{'errors': None,
                'good': True,
                'questionable': False,
                'substituted': False,
                'timestamp': '2021-02-01T21:40:00Z',
                'value': 59.99268,
                'web_exception': None}],
     'links': {'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegw7_MMAA'},
     'web_id': 'I1DPOGpIXSBWLkGcEkjIvyMegw7_MMAA'},
    {'items': [{'errors': None,
                'good': True,
                'questionable': False,
                'substituted': False,
                'timestamp': '2021-02-01T21:39:56.055191Z',
                'value': 304.8489,
                'web_exception': None}],
     'links': {'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegwuMYIAA'},
     'web_id': 'I1DPOGpIXSBWLkGcEkjIvyMegwuMYIAA'}
]

您的直接問題是您的索引與您的結構不匹配。 items是一個包含字典的列表,而不是字典本身。 正確的訪問順序是

print(regDataDict[0]['items'][0]['timestamp'])

哪個打印

2021-02-01T21:40:00Z

長期的問題是你你正在嘗試扁平化你的聽寫,但是:

  1. 看起來您仍在嘗試訪問結果,就好像它是原始結構一樣;
  2. 您的“展平”例程只是在整個原始值上添加一個空字符串鍵:您添加一個級別,而不是展平。

如果您出於某種原因需要展平結構,那么我們需要您指定生成的數據結構,並將您的代碼跟蹤到問題點。

特別是,我觀察到您習慣將 dict 作為列表的唯一元素括起來。 這似乎沒有提供任何組織利益。 如果不出意外,您的數據清理可能應該擺脫這個額外的級別。

OP,作為對 Prune 答案的補充,我是否可以為您的數據建議一種替代結構,其中web_id成為鍵,相關數據是內部字典:

_items = {
    'I1DPOGpIXSBWLkGcEkjIvyMegw8PMMAA': {
        'errors': None,
        'good': True,
        'questionable': False,
        'substituted': False,
        'timestamp': '2021-02-01T21:40:00Z',
        'value': -180.625427,
        'web_exception': None,
        'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegw8PMMAA'
    },
    'I1DPOGpIXSBWLkGcEkjIvyMegw7_MMAA': {
        'errors': None,
        'good': True,
        'questionable': False,
        'substituted': False,
        'timestamp': '2021-02-01T21:40:00Z',
        'value': 59.99268,
        'web_exception': None,
        'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegw7_MMAA'
    },
    'I1DPOGpIXSBWLkGcEkjIvyMegwuMYIAA': {
        'errors': None,
        'good': True,
        'questionable': False,
        'substituted': False,
        'timestamp': '2021-02-01T21:40:00Z',
        'value': 304.8489,
        'web_exception': None,
        'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegwuMYIAA'
    }
}

我真的不知道您在做什么,並且我假設每個 object 的web_id都是唯一的(否則,使用_id非常具有誤導性)。 我只是想我會把它扔在那里,因為它會更容易使用。

假設您的輸入數據的結構是一致的,以下是您可以如何進行數據清理:

new_items = {}
for d in _items:
    new_items[d['web_id']] = {**d['items'][0]}
    new_items[d['web_id']]['source'] = d['links']['source']

如果您想要更簡潔的密鑰,您還可以從web_id中刪除常見的 substring:


new_items = {}
for d in _items:
    new_id = d['web_id'].replace('I1DPOGpIXSBWLkGcEkjIvyMeg', '')
    new_items[new_id] = {**d['items'][0]}
    new_items[new_id]['source'] = d['links']['source']

感謝大家,

我修改了我的方法,使其感覺更加面向對象,並避免了很多不必要的字典和列表操作。

  1. 將原始 object 轉換為字典。
  2. 將字典轉換為 Class。
  3. 以標准 OO 方式訪問 Class 成員。

我從 Kien Nguyen Trung 的精彩帖子中借用了 Class 結構: https://kiennt.com/blog/2012/06/14/python-object-and-dictionary-convertion.ZFC356EZ83A

class PiStruct(object):
      def __init__(self, **entries):
            self.__dict__.update(entries)

# convert to PI Response "Class" to Dictionary 
regDataDict = piItemsStreamValuesR.__dict__

# convert the Dictionary to a Class
classMembers = PiStruct(**regDataDict)

# Print the Class Members
for i in range(0,len(classMembers._items)): 
    for n in range(0,len(classMembers._items[i].items)):
        print('Timestamp:', classMembers._items[i].items[i].timestamp)
        print('Reading:', classMembers._items[i].items[i].value)
        print('Name:', classMembers._items[i].name)

原始 PI Object 類型:<class 'osisoft.pidevclub.piwebapi.models.pi_items_stream_values.PIItemsStreamValues'>

Timestamp: 2021-02-02T16:42:00Z
Reading: 145.6539
Name: Sample Name
Timestamp: 2021-02-02T16:42:00Z
Reading: 59.9942245
Name: Sample Name
Timestamp: 2021-02-02T16:41:20.4717254Z
Reading: -189.0652
Name: Sample Name

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM