Dunders In Python
#PEP 560: Core Support for typing module and Generic Types
The PEP introduces two special methods __class_getitem__()
and __mro_entries__
, these methods are now used by most classes and special constructs in typing. As a result, the speed of various operations with types increased up to 7 times, the generic types can be used without metaclass conflicts, and several long standing bugs in typing module are fixed.
#Callables with __call__
There is a way to make instance callable.
class prophecy:
def __call__(self, type_of_prefecy):
return self.grim() if type_of_prefecy == 'grim' else "no prophecy for you"
def grim(self):
return "we all gona die!"
p = prophecy()
print(p('grim'))
print(p("other_type_prophecy"))
> we all gona die!
> no prophecy for you
#Object Oriented Programming __init__
& __del__
Object constors and descructors.
class constr_destr:
def __init__(self):
print("i am alive")
def __del__(self):
print("i am dead")
c = constr_destr()
del c
> i am alive
> i am dead
#Ordering and Comparing
Ordering and Comparing things with __lt__
, __le__
, __gt__
, __ge__
and __eq__
. functools.total_ordering
decorator. Implementations any of this methods allows to compare objects. Usage of functools.total_ordering
allows to skipp full implmentation and limit only to two methods __eq__
and anyone of the list __lt__
, __le__
, __gt__
, __ge__
.
from functools import total_ordering
@total_ordering
class Weight:
def __init__(self, weight:str):
self.number, self.units = weight.split(" ")
@property
def value(self):
return self.converts_to_kilograms()
def converts_to_kilograms(self):
mesurments = {}
mesurments['gr'] = 0.001
mesurments['kg'] = 1
mesurments['quintal'] = 100
mesurments['pound'] = 0.5
mesurments['ton'] = 1000
return float(self.number)*mesurments.get(self.units)
def __gt__(self, other):
return self.value > other.value
def __eq__(self, other):
return self.value == other.value
Weight('5 kg') == Weight('5000 gr'), Weight('5 kg') < Weight('4999 gr'), Weight('5 kg') > Weight('4999 gr')
result >>> (True, False, True)
#Representation methods __repr__
& __str__
class ExampleRepr:
"represents x number "
def __init__(self, x = int):
self.x = x
def __repr__(self) -> str:
return "{}({})".format(self.__class__.__name__, self.x)
class ExampleStr(ExampleRepr):
def __str__(self):
return "{}".format(self.x)
class ExampleHTML(ExampleStr):
" method for classes to be used in jupyter to prepresent html "
def _repr_html_(self):
return "Value of x is <em>{}</em>".format(self.x)
# ic(ExampleRepr(2))
print(ExampleRepr(2))
# ic(ExampleStr(2))
print(ExampleStr(2))
ExampleHTML(2)
> ExampleRepr(2)
> 2
Value of x is 2
#Context Managers with __enter__
and __exit__
class ManagedFile:
def __init__(self, name):
self.name = name
def __enter__(self):
self.file = open(self.name, 'w')
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
if self.file:
self.file.close()
# So we can do something like implementing custom write or read
# or any other functionality.
with ManagedFile('hello.txt') as f:
f.write('¡holla!')
#Math Operations (regular ones) - overloading
class Math:
def __init__(self, a):
self._a = a
# --- regular math operators overloading
def __add__(self, b):
""" Addition with - """
return self.__class__(self.value + b.value)
def __sub__(self, b):
""" Subtraction with - """
return self.__class__(self.value - b.value)
def __mul__(self, b):
""" Multiplication with * """
return self.__class__(self.value * b.value)
def __mod__(self, b):
""" Modulus operation % """
return self.__class__(self.value % b.value)
def __rpow__(self, b):
print("not affected")
def __pow__(self, b):
""" powering value with ** """
return self.__class__(self.value ** b.value)
def __floordiv__(self, b):
""" Division with // """
return self.__class__(self.value // b.value)
def __truediv__(self, b):
""" Division with / """
return self.__class__(self.value / b.value)
def __divmod__(self, b):
return self.__floordiv__(b), self.__mod__(b)
def __matmul__(self, b):
""" matrix multiplication @ """
return self.__class__(self.value * b.value)
def __repr__(self):
return f"{self._a}"
@property
def value(self):
return self._a
Math(1)+Math(2),Math(1)-Math(2), Math(1)*Math(2), Math(1)/Math(2), Math(1)//Math(2), Math(1)**Math(2), Math(1)%Math(2), Math(1) @ Math(2), divmod(Math(1), Math(2)),
result >>> (3, -1, 2, 0.5, 0, 1, 1, 2, (0, 1))
#Math Operation (inplace and right-operated)
#todo
#TypeCasting
class TypeInt:
def __init__(self, n):
self.n = n
def __int__(self):
return self.n
def __str__(self):
return "one" if self.n == 1 else "I dont know, its complicated number".format(self.n)
def __float__(self):
return float(self.n)
def __bool__(self):
return True
int(TypeInt(1)), str(TypeInt(1)), float(TypeInt(1)), bool(TypeInt(0))
result >>> (1, 'one', 1.0, True)