Extending Types#
TypeView
subscripting can be used to set attributes on type objects, including built-in types.The
impl()
decorator can implement the decorated method onto a type.
Using the impl()
decorator#
Works for normal methods, dunder methods, or decorated static / class / property methods.
from einspect import impl
@impl(int)
def is_even(self):
return self % 2 == 0
print((2).is_even()) # True
@impl(int)
def __matmul__(self, other):
return self * other
print(5 @ 3) # 15
@impl(int)
@property
def real(self):
return self + 1
print((2).real) # 3
@impl(int)
@classmethod
def try_from(cls, x):
try:
return cls(x)
except ValueError:
return None
print(int.try_from('2')) # 2
print(int.try_from('a')) # None
@impl(list)
@staticmethod
def abc():
return "abc"
print(list.abc()) # "abc"
print([].abc()) # "abc"
Using orig
to get original attributes#
Sometimes you may want to defer to the original implementation of a method or attribute before it was overriden by impl
or TypeView
, in this case calling orig(<type>)
will return a proxy object of the type where attribute access will yield original attributes.
For example, we want to override the __add__
of floats, by adding a print statement, but we want to still call the original __add__
after our print.
Calling orig(float)
will give us the float proxy object, where orig(float).__add__
will give us the original float.__add__
method before our override.
from einspect import impl, orig
@impl(float)
def __add__(self, other):
print(f"Adding {self} and {other}")
return orig(float).__add__(self, other)
Using TypeView()
subscripting#
Views of types can be subscripted to either get or set attributes on the type. This works in all cases where @impl
can be used.
In addition, this form can also set static attributes like __dict__
or __name__
.
from einspect import view
v = view(int)
print(v["__name__"]) # int
v["is_even"] = lambda self: self % 2 == 0
print((2).is_even()) # True
v["__name__"] = "MyInt"
print(int.__name__) # MyInt
print(int) # <class 'MyInt'>
Multiple attributes can be set together by passing multiple attribute names.
from einspect import view
v = view(str)
v["__truediv__", "__floordiv__"] = str.split
print("Hello, world!" / ", ") # ['Hello', 'world!']
print("abc-xyz" // "-") # ['abc', 'xyz']