I heard from one guy that you should not use magic methods directly. and I think in some use cases I would have to use magic methods directly. So experienced devs, should I use python magic methods directly?
I intended to show some benefits of not using magic methods directly:
1- Readability:
Using built-in functions like len()
is much more readable than its relevant magic/special method __len__()
. Imagine a source code full of only magic methods instead of built-in function... thousands of underscores...
2- Comparison operators:
class C:
def __lt__(self, other):
print('__lt__ called')
class D:
pass
c = C()
d = D()
d > c
d.__gt__(c)
I haven't implemented __gt__
for neither of those classes, but in d > c
when Python sees that class D
doesn't have __gt__
, it checks to see if class C
implements __lt__
. It does, so we get '__lt__ called'
in output which isn't the case with d.__gt__(c)
.
3- Extra checks:
class C:
def __len__(self):
return 'boo'
obj = C()
print(obj.__len__()) # fine
print(len(obj)) # error
or:
class C:
def __str__(self):
return 10
obj = C()
print(obj.__str__()) # fine
print(str(obj)) # error
As you see, when Python calls that magic methods implicitly, it does some extra checks as well.
4- This is the least important but using let's say len()
on built-in data types such as str
gives a little bit of speed as compared to __len__()
:
from timeit import timeit
string = 'abcdefghijklmn'
print(timeit("len(string)", globals=globals(), number=10_000_000))
print(timeit("string.__len__()", globals=globals(), number=10_000_000))
output:
0.5442426
0.8312854999999999
It's because of the lookup process(__len__
in the namespace), If you create a bound method before timing, it's gonna be faster.
bound_method = string.__len__
print(timeit("bound_method()", globals=globals(), number=10_000_000))
I'm not a senior developer, but my experience says that you shouldn't call magic methods directly.
Magic methods should be used to override a behavior on your object. For example, if you want to define how does your object is built, you override __init__
. Afterwards when you want to initialize it, you use MyNewObject()
instead of MyNewObject.__init__()
.
For me, I tend to appreciate the answer given by Alex Martelli here:
When you see a call to the
len
built-in, you're sure that, if the program continues after that rather than raising an exception, the call has returned an integer, non-negative, and less than 2**31 -- when you see a call toxxx.__len__()
, you have no certainty (except that the code's author is either unfamiliar with Python or up to no good;-).
If you want to know more about Python's magic methods, I strongly recommend taking a look on this documentation made by Rafe Kettler: https://rszalski.github.io/magicmethods/
No you shouldn't.
it's ok to be used in quick code problems like in hackerrank but not in production code. when I asked this question I used them as first class functions. what I mean is, I used xlen = x.__mod__
instead of xlen = lamda y: x % y
which was more convenient. it's ok to use these kinda snippets in simple programs but not in any other case.
© 2022 - 2024 — McMap. All rights reserved.
__add__
is not responsible for the entirety of a+
operation,__getattribute__
is not the whole attribute access protocol, and not all iterables have an__iter__
method. – Ralline