formations/python-avancé/examples/metaclass-introspect.py

67 lines
1.8 KiB
Python

from functools import wraps
from time import perf_counter, sleep
from typing import Self
def as_call(args, kwargs):
passed = ['self']
for arg in args[1:]:
passed.append(repr(arg))
for key, value in kwargs.items():
passed.append(f"key={value!r}")
return "(" + ", ".join(passed) + ")"
def introspected_method(clsname, ctx, name, method):
def _(*args, **kwargs):
callstr = f"{clsname}.{name}{as_call(args, kwargs)}"
print(f"{'| ' * ctx['depth']}Calling {callstr}...")
ctx["depth"] += 1
before = perf_counter()
result = method(*args, **kwargs)
after = perf_counter()
ctx["depth"] -= 1
callstr = f"{clsname}.{name}{as_call(args, kwargs)}"
print(
f"{'| ' * ctx['depth']}Returning from {callstr} after {after-before:.2f}s with {result}"
)
return result
return _
class Introspected(type):
def __new__(cls, name, bases, ns, **kwds):
ctx = {"depth": 0}
for key, value in ns.items():
if callable(value) and key != "__repr__":
ns[key] = introspected_method(name, ctx, key, value)
return super().__new__(cls, name, bases, ns, **kwds)
class Point(metaclass=Introspected):
def __init__(self, x, y):
self.x = x
self.y = y
def dist(self, other: Self) -> float:
return ((other.x - self.x) ** 2 + (other.y - self.y) ** 2) ** 0.5
def __repr__(self):
return f"Point(x={self.x!r}, y={self.y!r})"
def modulus(self):
return self.dist(Point(0, 0))
def recursive_call(self, value):
sleep(0.1)
if value:
return self.recursive_call(value - 1)
else:
return self.mean()
if __name__ == "__main__":
p = Point(10, 10)
print(p.modulus())