Error between datetime.date and NoneType operations in Python

2

Bearing in mind that partidos is a list with sublists containing tuples. Ex: partidos = [[(datetime.date(2000, 9, 9), 'FC Barcelona', 2, 'Málaga CF', 1)], [(datetime.date(2000, 9, 9), 'RC Deportivo', 2, 'Athletic Club', 0)], [(datetime.date(2000, 9, 9), 'Real Sociedad', 2, 'R. Racing C.', 2)]]

I tried to build the following function so that it does what it asks:

def partidos_por_fecha(partidos, inicio=None, fin=None):
    ''' Filtra los partidos jugados en un rango de fechas

    ENTRADA: 
    - partidos: lista de partidos -> [Partido(datetime.date, str, int, str, int)]
    - inicio: fecha inicial del rango -> datetime.date
    - fin: fecha final del rango -> datetime.date
    SALIDA: 
    - lista de partidos seleccionados -> [Partido(datetime.date, str, int, str, int)] 

    Se devuelven aquellos partidos que se han jugado entre las fechas inicio
    y fin. Ambos parámetros serán objetos date del módulo datetime.
    Si inicio es None, se incluirán los partidos desde el principio de
    la serie, y si fin es None se inlcuirán los partidos hasta el último de
    la serie.
    '''
    if inicio == None:
        inicio = partidos[0][0][0]
    elif fin == None:
        fin = partidos[-1][-1][0]
    elif inicio == None and fin == None:
        inicio = partidos[0][0][0]
        fin = partidos[-1][-1][0]
    else:
        inicio == inicio
        fin == fin

    result = []
    for i in partidos:
        for fecha, local, goles_local, visitante, goles_visitante in i:
            if fecha >= inicio and fecha <= fin:
                result.append((fecha, local, goles_local, visitante, goles_visitante))
    return result

This function is executed by the following code:

def test_partidos_por_fechas(partidos):
    inicio = datetime(2007, 9, 15).date()
    fin = datetime(2008, 7, 1).date()
    print(len(partidos_por_fecha(partidos, inicio, fin)))
    print(len(partidos_por_fecha(partidos, inicio, None)))
    print(len(partidos_por_fecha(partidos, None, fin)))
    print(len(partidos_por_fecha(partidos, None, None)))

test_partidos_por_fechas(partidos)

The error that I get after executing the function is: TypeError: '<=' not supported between instances of 'datetime.date' and 'NoneType' And it tells me that it is in the if that is inside the loops for . I do not understand how after filtering the arguments inicio and fin when they have None before loops for , I keep entering variables None to compare with datetimes

I would like to get some solution for the function to work. I'm sorry if there are errors of indentation in the code to have passed it here and thanks in advance.

    
asked by Jesus_jbs 09.12.2018 в 12:18
source

1 answer

2

There are some errors in the code,:

  • The comparison with None is recommended to be through the operator is , ie if inicio is None , etc. instead of if inicio == None . The reason for this is quite technical (if you have interest I can explain it in a final note).

    In this particular case this detail does not affect the operation of the code, but get used to doing it with is as a general rule.

  • In the else: you have a == where I think you wanted to make an assignment ( = ). This does not even matter because it never enters the else , as we'll see right away, but obviously it was wrong.

  • The most important fault is the logic of the if with which you want to assign values to inicio and fin in case they do not have one. Note that if both are None , the first if inicio == None: will be fulfilled, and your body will be executed without running any of the other cases , so in that case fin will stay with its value% co_of initial%, and this case is the one that "breaks" you.

The simplest solution would be the following:

if inicio is None:
    inicio = partidos[0][0][0]
if fin is None:
    fin = partidos[-1][-1][0]

That is, I use a second None instead of a if . If elif is inicio , it is assigned a default value. Then, independently, the same is done with None . If both were fin , both will be assigned. The strange allocation None you had in the inicio=inicio; fin=fin is obviously not necessary, it leaves the variables as they were.

Another possibility

In some python codes you can find the following "trick". Personally I have contradictory feelings about it. On the one hand, the number of lines of code is reduced. On the other hand it makes use of a "rare" characteristic that can be considered to be not very readable. Although if you get used to seeing it, it ends up being quite readable ...

It's like this:

inicio = inicio or partidos[0][0][0]
fin = fin or partidos[-1][-1][0]

It can almost be read effortlessly as "assign to else: what was in inicio , or this other value (if what was in inicio was inicio )" .

The reason it works is because the result of a None expression in Python is the value of the last evaluated term that makes the expression true, or that of the last term if none is true.

Thus, if for example or is 20, inicio is true, (since 20 is considered as inicio or otra_cosa when it is part of a boolean expression, and therefore the expression is true already by only evaluating the first term, so the second is not evaluated), and the result would be True . However, if 20 is inicio (or zero, or the empty string, or another value that is considered None by python) then python must evaluate False to determine the result of otra_cosa . The final result of the expression will be the value of or .

It's a rare hack , and I do not know whether to recommend its use or to discourage it, but you should know it because you'll see it written there many times.

Finally python also has something equivalent to the ternary operator of C, otra_cosa , which in python would be v = condicion?valor_cierto:valor_falso .

Using this in your case:

inicio = partidos[0][0][0] if inicio is None else inicio
fin = partidos[-1][-1][0] if fin is None else fin

This in the background is just another way to put in less lines the v = valor_cierto if condicion else valor_falso that I put in the first part of the answer. I almost prefer the "in more lines" version because it's clearer.

    
answered by 09.12.2018 / 12:31
source