0

Is there a way to improve this code to make it shorter?

if date_a is None and date_b is None and date_c is None: 
    start_date = current_date
else:
    if date_a is not None:
        start_date = date_a
    elif date_b is not None:
        start_date = date_b
    elif date_c is not None:
        start_date = date_c
Forna
  • 81
  • 1
  • 8
  • `start_date = date_a or date_b or date_c or current_date` would work, assuming that no possible value of these variables (other than `None`) is a "falsy" value (zero, empty string, empty container, etc.) – jasonharper Aug 01 '21 at 22:33

4 Answers4

2

As an alternative in Python >= 3.8 you can use an assignment expression plus any():

any(start_date := d for d in (date_a, date_b, date_c, current_date))

In your specific case I suspect that a chain of or would be faster, however any() will also work well if you have a collection of variables and not just single variables with different names:

any(start_date := d for d in dates)

The return value of any will let you know whether there was some truthy value or not.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
  • Nice, no idea this existed. – William Aug 01 '21 at 22:38
  • Interesting. I tested it and I was wondering, why is 'any' required? Why I cannot just do: `(start_date := d for d in (date_a, date_b, date_c, current_date))` – Forna Aug 01 '21 at 23:17
  • 1
    @Forna because `any` will stop at the first item that is truthy, while what you wrote will simply go through all the elements and you will always end up with the last one being assigned to `start_date` after that statement. – Marco Bonelli Aug 01 '21 at 23:21
  • IMO `any(start_date := d for d in (date_a, date_b, date_c, current_date))` should *never* pass any sane code review – juanpa.arrivillaga Aug 02 '21 at 18:58
  • @juanpa.arrivillaga yeah, I feel like I have to agree there. – Marco Bonelli Aug 02 '21 at 19:02
1

You can use or, which will give you the first truthy value:

start_date = date_a or date_b or date_c or current_date

Another solution would be to turn them into an iterable, add an is None filter, and pull the first item using next():

start_date = next(date for date in (
    date_a, 
    date_b, 
    date_c, 
    current_date
) if date is not None)

This approach works better if you need a condition other than "truthiness", or if you have a lot of values (in which case organizing them in an iterable container is likely easier than pasting them into a long or sequence).

Samwise
  • 68,105
  • 3
  • 30
  • 44
1

First, you can remove one if/else depth:

if date_a is not None:
    start_date = date_a
elif date_b is not None:
    start_date = date_b
elif date_c is not None:
    start_date = date_c
else:
    start_date = current_date

You could also take advantage of the for...else statement:

for start_date in (date_a, date_b, date_c):
    if start_date is not None:
        break
else:
    start_date = current_date

The else only happens if none of the break conditions triggered, e.g. if all of the potential start_date's were None.

Pi Marillion
  • 4,465
  • 1
  • 19
  • 20
0

You can do something like:

start_date = date_a or date_b or date_c or current_date

Alternatively, there really is nothing wrong with:

if date_a is not None:
    start_date = date_a
elif date_b is not None:
    start_date = date_b
elif date_c is not None:
    start_date = date_c
else:
    start_date = current_date
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172