Hay 2 dictos de parámetros:

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"}}

Y

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'}]}

}

En el código no puedo mantener los parámetros y quiero extraerlos de un archivo json. Después de cargar el archivo, todas las fechas deben convertirse del formato str a datetime.

Este proceso se logra a través de varios bucles:

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

Pero el código es realmente feo y DRY es violado. ¿Hay mejores formas de iterar a través de dics anidados y cambiar los valores de ciertas claves?

0
Anna Dmitrieva 1 oct. 2019 a las 16:16

4 respuestas

La mejor respuesta

Esto es un poco más compacto:

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
Scott Hunter 1 oct. 2019 a las 13:21

Considere una comprensión de diccionario anidada y una función de mapeo dict para la conversión de tiempo:

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()}
1
Parfait 1 oct. 2019 a las 14:06

No soy un desarrollador de Python, pero puedo ver que está haciendo un bucle 4 veces sobre los mismos datos, cuando debe hacerlo solo una vez:

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

Código no probado, pero extraería la lógica común a una función y solo tendría un bucle foreach.

1
Exadra37 1 oct. 2019 a las 13:34

En lugar de iterar sobre un dict anidado después de cargar json, debe usar el método object_hook de json.loads () para deserializar las fechas en la importación (supongo que está usando la biblioteca json incorporada para analizar json).

Esto ya ha sido respondido, por favor, eche un vistazo a este hilo: Cómo convertir a un objeto de fecha y hora de Python con JSON .loads?

1
Paweł Szmajda 1 oct. 2019 a las 13:42
58185606