以更优雅、更高效的方式遍历嵌套字典?



有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转换为日期时间格式。

此过程通过几个循环来实现:

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。有没有更好的方法来迭代嵌套的dics并更改某些键的值?

这更紧凑一些:

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')

我不是 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 循环。

而不是在加载 json 后迭代嵌套字典,您需要使用 json.loads(( 的object_hook方法在导入时反序列化日期(我假设您使用内置的 json 库来解析 json(。

这已经回答了,请看一下这个线程: 如何使用JSON.loads转换为Python日期时间对象?

考虑一个嵌套字典理解和一个用于时间转换的字典映射函数:

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()}

最新更新