print() is fine for quick experiments. In a real program you want more control: messages carry a level, and one setting decides how much detail reaches the screen.The
logging module gives every message a severity tag:- DEBUG – development noise
- INFO – normal milestones (user logged in, order placed)
- WARNING – something unexpected but handled
- ERROR – an operation failed
- CRITICAL – the program cannot continue
logging.basicConfig() sets up the root logger, which every other logger passes its messages up to. The two arguments that matter here:level=logging.INFO – messages below INFO (i.e. DEBUG) are silently dropped.stream=sys.stdout – send the text to standard output so this course can read it.import logging
import sys
logging.basicConfig(
level=logging.INFO,
format='%(levelname)s:%(name)s:%(message)s',
stream=sys.stdout,
force=True,
)
logger = logging.getLogger('shop')
logger.debug('building cart for user 42') # hidden (DEBUG < INFO)
logger.info('order placed: item=book qty=1')Notice the output is one line:
The DEBUG line never appears. If you later set
INFO:shop:order placed: item=book qty=1The DEBUG line never appears. If you later set
level=logging.DEBUG, that same logger.debug(...) call prints, and the call itself never changes.Quick statistics with statistics
import statistics
data = [2.5, 3.0, 4.5, 6.0]
print(statistics.mean(data)) # average
print(statistics.median(data)) # middle value (or midpoint of two middles)
print(statistics.mode([1, 1, 2]))# most frequent value
print(round(statistics.stdev([2, 4, 6]), 3))Measuring how long code takes
import time
t0 = time.perf_counter()
for i in range(1_000):
pass
elapsed = time.perf_counter() - t0
print(f'{elapsed:.6f} seconds')timeit.timeit runs a function many times and returns the total wall-clock seconds. It is handy for comparing two implementations without writing your own loop.import timeit
def square(n):
return n * n
total = timeit.timeit(lambda: square(12), number=1000)
print(f'{total:.6f} seconds for 1000 calls')