19

So when coding I really like to use list comprehensions to transform data and I try to avoid for loops. Now I discovered that the walrus operator can be really handy for this, but when I try to use it in my code it doesn't seem to work. I've got the following code and want to transform the strings containing data about the timestamps into datetime objects in one easy line, but I get an syntax error and I am not sure what the right syntax would be, does anyone know what I did wrong?

from datetime import datetime

timestamps = ['30:02:17:36',
              '26:07:44:25','25:19:30:38','25:07:40:47','24:18:29:05','24:06:13:15','23:17:36:39',
              '23:00:14:52','22:07:04:33','21:15:42:20','21:04:27:53',
              '20:12:09:22','19:21:46:25']

timestamps_dt = [
    datetime(days=day,hours=hour,minutes=mins,seconds=sec) 
    for i in timestamps
    day,hour,mins,sec := i.split(':')
] 

kennysliding
  • 2,783
  • 1
  • 10
  • 31
Jeroen Vermunt
  • 672
  • 1
  • 6
  • 19
  • 2
    The walrus operator has to be part of a valid expression. At that point no expression is syntactically allowed. – Klaus D. Nov 26 '20 at 15:03
  • `[... for d, h, m, s in (i.split(':') for i in timestamps)]`… – deceze Nov 26 '20 at 15:04
  • @deceze solution is correct. But the Pythonic way of doing what you original wrote is `.... for days, hours, mins, secs in [i.split(':')]`. Iterating over a singleton list is the idiomatic way of setting values in a for loop. – Frank Yellin Nov 26 '20 at 15:09

2 Answers2

23

Since Walrus operator does not support values unpacking, the operation

day,hour,mins,sec := i.split(':')

is invalid.

Walrus operator is recommended to be used mostly in logic comparison, especially when you need to reuse a variable in comparison. Therefore, I would argue that for this case, a simple datetime.strptime() would be better for this case.

If you must use walrus comparison in your list comprehension, you may do

from datetime import datetime

timestamps = ['30:02:17:36',
              '26:07:44:25','25:19:30:38','25:07:40:47','24:18:29:05','24:06:13:15','23:17:36:39',
              '23:00:14:52','22:07:04:33','21:15:42:20','21:04:27:53',
              '20:12:09:22','19:21:46:25']

timestamps_dt = [
    datetime(2020,11, *map(int, time)) # map them from str to int
    for i in timestamps
    if (time := i.split(':')) # assign the list to the variable time
]
print(timestamps_dt)

But then it will lead to a question why not just,

timestamps_dt = [
    datetime(2020,11, *map(int, i.split(':'))) 
    for i in timestamps
]

Reference PEP-572

kennysliding
  • 2,783
  • 1
  • 10
  • 31
7

...and want to transform the strings containing data about the timestamps into datetime objects in one easy line,

If you want to convert the list of strings into a list of datetime objects you can use the below one liner:

timestamps_dt = [datetime.strptime(d, '%d:%H:%M:%S') for d in timestamps]
balderman
  • 22,927
  • 7
  • 34
  • 52
  • 3
    Way better approach, since this also handles the values as strings. Otherwise they'd need to be cast to ints as well. – deceze Nov 26 '20 at 15:15