更优雅,更有效的方式来迭代嵌套字典?

时间:2019-10-01 13:16:37

标签: python loops dictionary

参数有2个字典:

fb_config = {
  "page_likes" : {
    "page_id": "1111",
                       "metric": "page_fans",
                       "since": "2019-01-01 00:00:00",
                       "until": "2019-01-01 00:00:00",
                       "date_preset" : "yesterday",
                       "period": "day"},

    "page_impressions" : {"page_id": "1111",
                       "metric": "page_impressions",
                       "since": "yesterday",
                       "until": "yesterday",
                       "date_preset" : "yesterday",
                       "period": "day"},

    "page_engaged_users" : {"page_id": "1111",
                       "metric": "page_engaged_users",
                       "since": "today",
                       "until": "today",
                       "date_preset" : "yesterday",
                       "period": "day"}}

ga_config =

{

'view_id_123': {'view_id': '123',
                           'start_date': "2019-01-01 00:00:00",
                           'end_date': "2019-01-01 00:00:00",
                           'metrics': [{'expression': 'ga:sessions'}, {'expression':'ga:pageviews'}, {'expression':'ga:users'}, {'expression':'ga:bounces'},
                          {'expression':'ga:avgSessionDuration'}],
                           'dimensions': [{'name': 'ga:year'}, {'name': 'ga:userType'}, {'name': 'ga:sessionCount'}, {'name': 'ga:browser'},
                                          {'name': 'ga:source'}]},

'view_id_456': {'view_id': '456',
                           'start_date': "today",
                           'end_date': "today",
                           'metrics': [{'expression': 'ga:bounces'}, {'expression':'ga:users'}],
                           'dimensions': [{'name': 'ga:mobileDeviceModel'}, {'name': 'ga:dataSource'}]},

'view_id_789': {'view_id': '789',
                           'start_date': "yesterday",
                           'end_date': "yesterday",
                           'metrics': [{'expression': 'ga:bounces'}, {'expression':'ga:users'}],
                           'dimensions': [{'name': 'ga:mobileDeviceModel'}, {'name': 'ga:dataSource'}]}

}

在代码中,我无法保留参数,而是想从json文件中提取它们。加载文件后,所有日期都必须从str转换为datetime格式。

此过程通过以下几个循环完成:

for values in params.values():
    if 'since' in values:
        if values['since'] == 'today':
            values['since'] = datetime.now()
        elif values['since'] == 'yesterday':
            values['since'] = datetime.now() - timedelta(1)
        else: 
            values['since'] = dt.datetime.strptime(values['since'], '%Y-%m-%d %H:%M:%S')

for values in params.values():
    if 'until' in y:
        if values['until'] == 'today':
            values['until'] = datetime.now()
        elif values['until'] == 'yesterday':
            values['until'] = datetime.now() - timedelta(1)
        else:
            values['until'] = dt.datetime.strptime(y['until'], '%Y-%m-%d %H:%M:%S')

for values in params.values():
    if 'start_date' in values:
        if values['start_date'] == 'today':
            values['start_date'] = datetime.now()
        elif values['start_date'] == 'yesterday':
            values['start_date'] = datetime.now() - timedelta(1)
        else:
            values['start_date'] = dt.datetime.strptime(values['start_date'], '%Y-%m-%d %H:%M:%S')

for values in params.values():
    if 'end_date' in values:
        if values['end_date'] == 'today':
            values['end_date'] = datetime.now()
        elif values['end_date'] == 'yesterday':
            values['end_date'] = datetime.now() - timedelta(1)
        else:
            values['end_date'] = dt.datetime.strptime(values['end_date'], '%Y-%m-%d %H:%M:%S')

但是代码确实很丑,并且违反了DRY。是否有更好的方法来遍历嵌套dic并更改某些键的值?

4 个答案:

答案 0 :(得分:1)

这有点紧凑:

for values in params.values():
    for k in ('since','until','start_date','end_date'):
        if k in values:
            if values[k] == 'today':
                values[k] = datetime.now()
            elif values[k] == 'yesterday':
                values[k] = datetime.now() - timedelta(1)
            else: 
                values[k] = dt.datetime.strptime(values[k], '%Y-%m-%d %H:%M:%S')

答案 1 :(得分:1)

我不是Python开发人员,但是我可以看到您在同一数据上循环了4次,而您只应该执行一次:

def formatDate(value, default):
    if value == 'today':
        date = datetime.now()
    elif value == 'yesterday':
        date = datetime.now() - timedelta(1)
    else:
        date = default

    return date

def your_function():

    for values in params.values():
        if 'since' in values:
            values['since'] = formatDate(values['since'], dt.datetime.strptime(values['since'], '%Y-%m-%d %H:%M:%S'))

        if 'until' in values:
            values['until'] = formatDate(values['until'], dt.datetime.strptime(y['until'], '%Y-%m-%d %H:%M:%S'))

        if 'start_date' in values:
            values['start_date'] = formatDate(values['start_date'], dt.datetime.strptime(values['start_date'], '%Y-%m-%d %H:%M:%S'))

        if 'end_date' in values:
            values['end_date'] = formatDate(values['end_date'], dt.datetime.strptime(values['end_date'], '%Y-%m-%d %H:%M:%S'))

代码未经测试,但是我将通用逻辑提取到一个函数中,并且只有一个foreach循环。

答案 2 :(得分:1)

加载json之后,您无需使用嵌套的dict进行迭代,而是需要使用json.loads()的object_hook方法对导入时的日期进行反序列化(我假设您正在使用内置的json库来解析json)。

已经回答了,请看一下这个线程: How to convert to a Python datetime object with JSON.loads?

答案 3 :(得分:1)

考虑嵌套字典理解和字典映射函数以进行时间转换:

def time_conversion(arg):
    switcher = {
        'today': datetime.now(),
        'yesterday': datetime.now() - timedelta(1)
    }

    output = (datetime.strptime(arg, '%Y-%m-%d %H:%M:%S') 
                  if arg not in switcher.keys() else switcher.get(arg))
    return output


new_params = {outer_k:{inner_k: time_conversion(inner_v) 
                          if inner_k in ('since', 'until', 'date_preset') else inner_v 
                       for inner_k, inner_v in outer_v.items()} 
              for outer_k, outer_v in params.items()}