Python avancé: Some examples.
This commit is contained in:
parent
596e9c5ae1
commit
e37af50649
|
@ -0,0 +1,28 @@
|
|||
# This is the creation « from scratch » of the following class:
|
||||
|
||||
# class Foo:
|
||||
# def say(self):
|
||||
# print("hello")
|
||||
|
||||
# First the type.__prepare__ is called to create a namespace, it
|
||||
# typically returns a fresh empty dict:
|
||||
|
||||
ns = {}
|
||||
|
||||
# Then the class body is executed in this namespace:
|
||||
|
||||
exec(
|
||||
"""
|
||||
def say(self):
|
||||
print("hello")
|
||||
""",
|
||||
globals(),
|
||||
ns,
|
||||
)
|
||||
|
||||
# Now, the type __new__ is called to create the class:
|
||||
|
||||
Foo = type.__new__(type, "Foo", (), ns)
|
||||
type.__init__(Foo, "Foo", (), ns) # Does nothing
|
||||
|
||||
Foo().say()
|
|
@ -0,0 +1,39 @@
|
|||
from urllib.parse import parse_qsl
|
||||
|
||||
|
||||
class Application:
|
||||
def __init__(self):
|
||||
self.routes = {}
|
||||
|
||||
def route(self, path):
|
||||
def deco(fct):
|
||||
self.routes[path] = fct
|
||||
return fct
|
||||
return deco
|
||||
|
||||
def get(self, path):
|
||||
try:
|
||||
path, qs = path.split("?", maxsplit=1)
|
||||
except ValueError:
|
||||
qs = {}
|
||||
return self.routes[path](**dict(parse_qsl(qs)))
|
||||
|
||||
app = Application()
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def home():
|
||||
return "<a href='/api'>/api</a>"
|
||||
|
||||
@app.route("/api")
|
||||
def api():
|
||||
return {"version": "1"}
|
||||
|
||||
@app.route("/auth/")
|
||||
def auth(username, password):
|
||||
return f"Wrong password for {username}"
|
||||
|
||||
|
||||
print(app.get("/"))
|
||||
print(app.get("/api"))
|
||||
print(app.get("/auth/?username=mdk&password=test"))
|
|
@ -0,0 +1,19 @@
|
|||
def memoize(limit): # Factory
|
||||
def _memoize(function_fib):
|
||||
memory = {}
|
||||
def cached_fib(n):
|
||||
if n in memory:
|
||||
return memory[n]
|
||||
result = function_fib(n)
|
||||
memory[n] = result
|
||||
return result
|
||||
return cached_fib
|
||||
return _memoize
|
||||
|
||||
@memoize(limit=1024)
|
||||
def fib(n):
|
||||
if n < 2:
|
||||
return 1
|
||||
return fib(n-1) + fib(n-2)
|
||||
|
||||
# fib = memoize(limit=1024)(fib)
|
|
@ -0,0 +1,33 @@
|
|||
class PositiveInteger:
|
||||
def __set_name__(self, owner, name):
|
||||
self.name = name
|
||||
|
||||
def __get__(self, instance, cls=None):
|
||||
if instance is None:
|
||||
return self
|
||||
return instance.__dict__[self.name]
|
||||
|
||||
def __set__(self, instance, value):
|
||||
if value < 0:
|
||||
raise ValueError("Negative values are not acceptable.")
|
||||
instance.__dict__[self.name] = value
|
||||
|
||||
|
||||
class Order:
|
||||
qty = PositiveInteger()
|
||||
price = PositiveInteger()
|
||||
|
||||
def __init__(self, item, price, qty):
|
||||
self.item = item
|
||||
self.price = price
|
||||
self.qty = qty
|
||||
|
||||
def cost(self):
|
||||
return self.price * self.qty
|
||||
|
||||
|
||||
# Order("un truc", -1, 1)
|
||||
# o = Order("Un livre", 35, 1)
|
||||
# o.qty += 1
|
||||
# o.qty -= 10
|
||||
# print(o.cost())
|
|
@ -0,0 +1,14 @@
|
|||
from string import ascii_letters
|
||||
|
||||
from hypothesis import given, settings
|
||||
|
||||
from hypothesis.strategies import text, lists
|
||||
|
||||
|
||||
@given(lists(text(alphabet=ascii_letters, max_size=10)))
|
||||
@settings(max_examples=500)
|
||||
def test_sort_is_stable(a_list):
|
||||
print(a_list)
|
||||
double_sort = sorted(sorted(a_list, key=str.lower), key=len)
|
||||
single_sort = sorted(a_list, key=lambda s: (len(s), s.lower()))
|
||||
assert double_sort == single_sort
|
|
@ -0,0 +1,27 @@
|
|||
class AutoInit(type):
|
||||
def __new__(mcs, name, bases, ns, **kwargs):
|
||||
cls = type.__new__(mcs, name, bases, ns)
|
||||
cls._attributes = kwargs["attributes"]
|
||||
return cls
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
attributes = {}
|
||||
for name in self._attributes:
|
||||
attributes[name] = kwargs.pop(name, None)
|
||||
obj = super().__call__(*args, **kwargs)
|
||||
for key, value in attributes.items():
|
||||
setattr(obj, key, value)
|
||||
return obj
|
||||
|
||||
|
||||
class Point(metaclass=AutoInit, attributes=("x", "y", "z")):
|
||||
...
|
||||
|
||||
|
||||
origin = Point(x=0, y=0, z=0)
|
||||
print(origin.x, origin.y, origin.z) # 0 0 0
|
||||
|
||||
NonePoint = Point()
|
||||
print(NonePoint.x, NonePoint.y) # None None
|
||||
|
||||
# origin = Point(x=0, y=0, blah=42) # TypeError !
|
|
@ -0,0 +1,66 @@
|
|||
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())
|
|
@ -0,0 +1,26 @@
|
|||
class StronglyTypedMeta(type):
|
||||
def __new__(cls, name, bases, ns, **kwds):
|
||||
if '__annotations__' in ns:
|
||||
for name, type in ns['__annotations__'].items():
|
||||
ns[name] = StronglyTypedDescriptor(name, type)
|
||||
return super().__new__(cls, name, bases, ns, **kwds)
|
||||
|
||||
|
||||
class StronglyTypedDescriptor:
|
||||
def __init__(self, name, type):
|
||||
self.name = name
|
||||
self.type = type
|
||||
|
||||
def __get__(self, instance, cls=None):
|
||||
return instance.__dict__[self.name]
|
||||
|
||||
def __set__(self, instance, value):
|
||||
if not isinstance(value, self.type):
|
||||
raise TypeError(f"{self.name} should be of type {self.type}.")
|
||||
instance.__dict__[self.name] = value
|
||||
|
||||
|
||||
|
||||
class Test(metaclass=StronglyTypedMeta):
|
||||
x: str
|
||||
y: int
|
|
@ -0,0 +1,70 @@
|
|||
class Meta(type):
|
||||
@classmethod
|
||||
def __prepare__(metacls, name, bases, **kwds):
|
||||
"""Prepare the namespace in which the class will be executed."""
|
||||
print(
|
||||
"Meta.__prepare__(",
|
||||
f"{metacls=},",
|
||||
f"{name=},",
|
||||
f"{bases=},",
|
||||
f"{kwds=}) -> {{}}",
|
||||
sep="\n ",
|
||||
)
|
||||
return {}
|
||||
|
||||
# __new__() is a static method (special-cased so you need not declare it as such)
|
||||
def __new__(cls, name, bases, namespace, **kwds):
|
||||
"""The class body is executed in a new namespace and the class name is
|
||||
bound locally to the result of type(name, bases, namespace).
|
||||
"""
|
||||
print(
|
||||
"\nMeta.__new__(",
|
||||
f"{cls=},",
|
||||
f"{name=},",
|
||||
f"{bases=},",
|
||||
f"{namespace=}",
|
||||
f"{kwds=})",
|
||||
sep="\n ",
|
||||
end=" ",
|
||||
)
|
||||
returns = type.__new__(cls, name, bases, namespace)
|
||||
print(f"-> {returns}\n")
|
||||
return returns
|
||||
|
||||
def __init__(self, name, bases, namespace, **kwds):
|
||||
"""This is the actual creation of the class !
|
||||
|
||||
As a class is an instance of its type."""
|
||||
print(
|
||||
"Meta.__init__(",
|
||||
f"{self=},",
|
||||
f"{name=},",
|
||||
f"{bases=},",
|
||||
f"{namespace=},",
|
||||
f"{kwds=})",
|
||||
sep="\n ",
|
||||
end="\n\n"
|
||||
)
|
||||
|
||||
|
||||
class Classe(metaclass=Meta):
|
||||
|
||||
print("\nAfter Meta.__prepare__ is called, the interpreter executes the class body "
|
||||
"like:")
|
||||
print(" exec(body, globals(), ns)")
|
||||
print("with `ns` the dict returned from __prepare__")
|
||||
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
print(f"Classe.__new__({cls=}, {args=}, {kwargs=})")
|
||||
returns = object.__new__(cls)
|
||||
print(f" returns {returns}")
|
||||
return returns
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
print(f"Classe.__init__({self=}, {args=}, {kwargs=})")
|
||||
|
||||
|
||||
print("Will now instantiate a Classe()")
|
||||
|
||||
Classe()
|
|
@ -0,0 +1,44 @@
|
|||
from pathlib import Path
|
||||
|
||||
class Context:
|
||||
def __init__(self):
|
||||
print("Constructing context")
|
||||
|
||||
def __enter__(self):
|
||||
print("Entering context")
|
||||
return "Coucou"
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
print("Exiting context", exc_type)
|
||||
|
||||
# with Context() as ctx:
|
||||
# print("In context", ctx)
|
||||
|
||||
|
||||
from tempfile import NamedTemporaryFile
|
||||
import os
|
||||
|
||||
class InplaceEdit:
|
||||
def __init__(self, filename, encoding="UTF-8"):
|
||||
self.filename = filename
|
||||
self.ifile = open(filename, encoding=encoding)
|
||||
self.encoding = encoding
|
||||
self.tmpfile = NamedTemporaryFile(mode="w", delete=False, encoding=encoding, dir=Path(filename).parent)
|
||||
|
||||
def __enter__(self):
|
||||
return self.ifile, self.tmpfile
|
||||
|
||||
def __exit__(self, typ, value, tb):
|
||||
self.ifile.close()
|
||||
self.tmpfile.close()
|
||||
if typ is None:
|
||||
os.rename(self.tmpfile.name, self.filename)
|
||||
else:
|
||||
os.unlink(self.tmpfile.name)
|
||||
|
||||
# with open("/etc/hosts") as hosts, open("/etc/shadow") as shadow:
|
||||
# ...
|
||||
|
||||
with InplaceEdit("hosts.txt") as (ifile, ofile):
|
||||
for line in ifile:
|
||||
ofile.write(line.replace("www.mdk.fr", "mdk.fr"))
|
|
@ -1,26 +0,0 @@
|
|||
digraph Python {
|
||||
subgraph cluster_0 {
|
||||
node [style=filled];
|
||||
label = "Names";
|
||||
color = lightgrey;
|
||||
un;
|
||||
deux;
|
||||
trois;
|
||||
liste;
|
||||
}
|
||||
subgraph cluster_1 {
|
||||
node [style=filled];
|
||||
label = "Values";
|
||||
color = lightgrey;
|
||||
1;
|
||||
2;
|
||||
3;
|
||||
4;
|
||||
"[...]" -> 1;
|
||||
"[...]" -> 2;
|
||||
}
|
||||
un -> 1;
|
||||
deux -> 2;
|
||||
trois -> 3;
|
||||
liste -> "[...]";
|
||||
}
|
Loading…
Reference in New Issue