Functions in Python are objects. If this is the first time you read this sentence, then you will not get a lot from this article, but it will show you, that there is quite a lot to learn about Python. Anyway, what does this mean? It means that the functions can be treated like an object in any way – you may assign them to a variable, you may put them in a list and you may treat them as a Python object in any case you like.
The code below puts 3 functions in a list and calls them with a for loop. Something that you cannot do with #VBA:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def my_lower(text): return str.lower(text) + "..." def my_upper(text): return str.upper(text) + "!!!" def my_casefold(text): return str.casefold(text) + ":)" funcs = [my_lower, my_upper, my_casefold] for func in funcs: print(func) print(func("VitoshAcademy.com")) |
Anyway, the target of this article is to write some type of a logger. Loggers are these pieces of software, that you would consider useless until they do not save you 4 hours of debugging. Or blushing you in front of users, who are looking for a trouble to blame you and your old-fashioned VBA software (again VBA!).
Ok, so in this one, the idea of the current logger is to state 3 things:
- The function that was called in the order it was called;
- The arguments of the function that was called;
- The date and time at which the function was called, so you may have some fun debugging;
So, there are 2 ways to do it – go into any function you write and add some lines, printing code. It is actually not as bad as it may seem, you may actually do it. However, the better “pythonistic” way is to use decorators for this one. Thus, you create a single function like the one in my code info(func) and you add it on the top of any function, that you want to be embedded in it. Like in the code below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
from datetime import datetime import pytz def info(func): def wrapper(*args, **kwargs): tz_Sofia = pytz.timezone('Europe/Sofia') print('v---+---v---+---v') print(datetime.now(tz_Sofia).strftime("%Y %B %d - %H:%M:%S")) print(f'{func.__name__}() - has been called with args - {args} and kwargs - {kwargs}') print('^---+---^---+---^') result = func(*args, **kwargs) return result return wrapper @info def my_lower(text): return str.lower(text) + "..." @info def my_upper(text): return str.upper(text) + "!!!" @info def my_casefold(text): return str.casefold(text) + ":)" funcs = [my_lower, my_upper, my_casefold] for func in funcs: print(func) print(func("VitoshAcademy.com"),5) @info def some_random_function(a, b=5,c=6): return a + b print(some_random_function(5, b=67, c=5)) |
And as you can see printed on the console, the log takes Bulgarian time and nicely prints the date and the time:
That’s all folks! 🙂