2

I am quite new to Python. I am working on an application which uses lists of Datetime objects (from the datetime module).

I want to debug my app, so I print (or log) thoses lists, but it returns me this :

>>> print(list_with_datetimes_and_timedeltas) # print calls __str__ (by default), but list's __str__ calls the item's __repr__
[(None, 1, datetime.datetime(2020, 11, 1, 18, 44, 12, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'Paris, Madrid'))), (datetime.timedelta(seconds=110, microseconds=7), 1, datetime.datetime(2020, 11, 1, 18, 46, 2, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'Paris, Madrid'))), (datetime.timedelta(seconds=103, microseconds=5), 1, datetime.datetime(2020, 11, 1, 1) .....

Which is unreadable, and is due to the fact that the list.str() returns the repr of each items (from what I understood).

There is no problem with str of Datetimes and Timedeltas :

>>> print(my_list_with_datetimes_and_timedeltas[0][2])
2020-11-01 18:44:12+01:00 #which is what I would like in the list for the datetimes
>>> print(my_list_with_datetimes_and_timedeltas[1][0])
0:01:50.000007 #which is what I would like in the list for the timedeltas

I have thought about multiple solutions, but I really don't know how to choose and if they are even doable:

  • change builtins List behavior so that it returns __str__ representations of items instead of their __repr__, because I don't really see why it would return __repr__ of objects if I call __str__ on a list (but this really doesn't seem a good idea, and I don't even know if it's doable)
  • change buildtins __repr__ of Datetime objects in the module Datetime (also really doesn't seem to be a good idea)
  • as Dan said here, I can print([str(item) for item in mylist]), but I would have to do this for every line of every log every time I print a List (and it will not even work here because it is a list of tuple)
  • I also use a Logger (from logging). May it help if I change something there?

Do you have any solutions? (and reasons why Python chose that when we call str on a list it shows the repr of the items?)

  • 2
    Your first two possible solutions are definitely a nono. – deceze Mar 16 '21 at 11:02
  • 2
    Yes, you want to use more explicit logging statements, not just depend on the default behaviour. You could easily make a logging helper function that does `logging.info('Some dates: %s', list(map(str, dates)))`… – deceze Mar 16 '21 at 11:03
  • @deceze I understand how this would be a solution for lists of datetime objects, but how about lists of tuples of datetime objects ? Do I have to do a function for every hierarchy case ? Thanks a lot for your answer. – Robin Warrot Mar 16 '21 at 11:09
  • 1
    You could somewhat easily do a recursive function that turns all arbitrarily nested iterables into stringified lists… – deceze Mar 16 '21 at 11:11
  • 1
    @deceze I tried to get the depth with `nested_list_depth_func = lambda iterable: type(iterable) in (list, tuple) and max(map(nested_list_depth_func, iterable))+1`, but I don't know what to do after this to loop on every sublist on a certain depth to transform it to str, do you know what I could do ? (I have been trying for 45 min but I'm stuck after I got the depth, I am quite new to Python) – Robin Warrot Mar 16 '21 at 12:03
  • 4
    "and reasons why Python chose that when we call str on a list it shows the repr of the items?" because the str would often be confusing to unusable e.g. consider a list of strings, and the strings contain commas. The `__str__` of a string is itself, the `__repr__` quotes and escapes it. Meaning if list used `__str__` it would show a bunch of words with commas interspersed and no way to know the boundaries between the items. Likewise here if it used the `__str__` there would be no way to differentiate between actual datetime objects and timestamp strings. – Masklinn Mar 16 '21 at 12:10
  • @Masklinn, if when we call __repr__ of a list it shows __repr__ of items then ok. If when we call print on a list it shows __repr of items for clarity then ok. But then why would they choose to print to __str__ when called directly, and __repr__ when in a list ? And even more because I don't see any easy way to see __str__ of items when we explicitely call __str__ on the list (maybe I am wrong tho, I am quite new, I want to understand). – Robin Warrot Mar 16 '21 at 12:24
  • The `__str__` implementation of `list` decides to use the `repr` of its contents. As mentioned, because it would otherwise often be impossible to tell multiple items in the list apart. List knows that and chooses this way. The str and repr representations for a list are the same, as there’s no obvious answer to how they should differ. – deceze Mar 16 '21 at 12:33
  • I have semi-solution for my debugging problem : do you think I can just create a new inherited class from datetime, and just change the __repr__ to be the same as __str__ ? I think that creating a function to change items to string may be a bit heavy to reuse everywhere. – Robin Warrot Mar 16 '21 at 12:38
  • I also have another idea : what about a decorator, that I use when I declare the list, which would also print it with a log ? Do you think it may work ? – Robin Warrot Mar 17 '21 at 08:19

0 Answers0