00
Python mechanisms used by the library¶
Basic Python syntax is assumed. This preparation chapter explains the data model and metaprogramming that make the mathematical notation meaningful.
Later chapters ask you to connect a definition to +,
==, a dataclass option, or a decorator. None of those
connections requires guessing once Python's dispatch rules are explicit.
- why
a + bnormally starts ata.__add__(b); - how
@logreplaces a function with a wrapper; - which dataclass methods are generated and which this project suppresses;
- why a passing test is evidence about code, not a general proof.
Open the complete logging implementation and its tests when you need the context around an excerpt.
Operators are method dispatch¶
For a user-defined object, left + right asks the left operand to handle the
operation:
NotImplemented is a special return value, not an exception. It tells Python
that this method does not know the other operand and allows reflected dispatch,
such as right.__radd__(left), to continue. This becomes important when values
from different levels of the numeric tower interact.
A decorator changes the public callable¶
This is the central part of @log:
def outer(func):
@wraps(func)
def inner(*args, **kwargs):
result, message = func(*args, **kwargs)
if logger.isEnabledFor(log_level):
logger.log(
log_level,
message if isinstance(message, str) else message(),
)
return result
return inner
Writing @log(log_level=4) above __add__ is equivalent to assigning the
result of the decorator back to the same name:
The original method returns (result, message_factory). Callers see inner,
which returns only result. The factory is a zero-argument function so the
message is not built when tracing is disabled.
Dataclass generation is selective¶
@dataclass(frozen=True, slots=True, eq=False, repr=False)
class NaturalNumber:
pre: NaturalNumber | None = None
Here the dataclass generates initialization, but:
frozen=Trueprevents field reassignment after construction;slots=Trueprevents undeclared instance fields;eq=Falseleaves equality to the hand-written Peano rules;repr=Falseleaves structural display to the library.
Other classes use __post_init__ to validate generated initialization.
Polynomial uses init=False and writes its own initializer because
normalization must happen before coefficients are stored.
Tests check executable claims¶
The logging tests inspect both the public signature and the emitted trace:
def test_decorator_preserves_method_metadata(self) -> None:
self.assertEqual(N_ONE.__add__.__name__, "__add__")
self.assertTrue(hasattr(N_ONE.__add__, "__wrapped__"))
If an internal decorated method returns (3, message_factory),
what does the caller receive, and when is the factory invoked?
You now have the vocabulary needed to read the first construction without assuming any prior knowledge of its source.