Tips and Tricks
Get nested attribute with dot notation
Interesting application for the reduce function is to access attribute of
nested objects:
import functools
def get_attr(obj, attr):
return functools.reduce(getattr, attr.split('.'), obj)
import dataclasses
@dataclasses.dataclass
class Address:
city: str
@dataclasses.dataclass
class User:
name: str
address: Address
Now if we want to access the city of the user, we acually need to access the
address of the user and than the city of the address. Expressed in dot notation we
want to access address.city :
>>> address = Address('Sofia')
>>> user = User('john', address)
>>> print(get_attr(user, 'address.city'))
Sofia
Trying to access missing attribute results in AttributeError error:
>>> address = Address('Sofia')
>>> user = User('john', address)
>>> print(get_attr(user, 'floor'))
Traceback (most recent call last):
...
AttributeError: 'Address' object has no attribute 'floor'
This function has been included in pygems.core.shortcuts module.
Capture function execution time
The pygems.core.timer.Timer class implements the decorator protocol.
You can capture the execution time of a function using the pygems.core.timer.Timer class as decorator.
from pygems.core.timer import Timer
@Timer(stop_func=lambda t: print(f'{t.elapsed}s'))
def slow_function():
# do your work here
pass
Each time the slow_functoin() is called, the elapsed time for
the function execution is printed to the console.
>> slow_function()
3.1e-06s
The pygems.core.timer.Timer calls the passed stop_func function
when the function has finished its execution.
In the above example we pass a lambda function which simply prints the elapsed seconds.
You could make the timer to log a message:
import logging
from pygems.core.timer import Timer
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def stop_func(t:Timer, *args):
logger.info(f'{t.name}: elapsed {t.elapsed}s')
@Timer(name='slow_function', stop_func=stop_func)
def slow_function():
# do your work here
pass
Now when the slow_function is called a message is added to the log which includes
the name of the timer and the elapsed time.
>> slow_function()
INFO:__main__:slow_function: elapsed 6.499999983589078e-06s
Capture the execution time of Python block
pygems.core.timer.Timer implements the context manager protocol.
This can be used to capture the time required to execute a block of code in Python.
You can pass any function as stop_func argument to the Timer class.
The function will be called at the end of the block with the timer instance as
first argument.
>>> from pygems.core.timer import Timer
>>> with Timer(name='slow-block', stop_func=lambda t: print(f'{t.name}: {t.elapsed}s')):
>>> # run your code here
>>> pass
slow-block: 3.999999989900971e-06s
Similarly the execution time of the block could be logged using Python’s logging module:
>>> import logging
>>> from pygems.core.timer import Timer
>>> logging.basicConfig(level=logging.INFO)
>>> with Timer(name='slow-block', stop_func=lambda t: logging.info(f'{t.name}: {t.elapsed}s')):
>>> # run your code here
>>> pass
INFO:root:slow-block: 1.5699999948992627e-05s