Why does python use magic methods?

I recently played with Python, and one thing that I find a little strange is the widespread use of “magic methods”, for example. to make its length available, the object implements the def __len__(self) method, and then is called when writing len(obj) .

I'm just wondering why objects do not just define the len(self) method and call it directly as a member of the object, for example. obj.len() ? I'm sure there must be good reason for Python to do this the way it is done, but as a beginner, I haven't developed what they are yet.

+82
python magic-methods
Apr 17 '10 at 7:26
source share
7 answers

AFAIK, len is special in this regard and has historical roots.

Here is a quote from the FAQ :

Why does Python use methods for some functionality (e.g. list.index ()), but functions for others (e.g. len (list))?

The main reason is history. functions were used for those operations that were typical of a group of types and which should work even for objects that did not have methods in all (for example, tuples). It is also convenient to have a function that can easily be applied to amorphous object collection when using the Python functionality (map (), apply (), etc.).

In fact, the implementation is len (), max (), min (), since the built-in function is actually less code than implementing them as methods for each type. You can be punished about individual cases, but it's part of Python, and it's too late to make such fundamental changes now. Functions must remain avoid massive code corruption.

Other "magic methods" (actually called a special method in Python folklore) make a lot of sense, and similar functionality exists in other languages. They are mainly used for code that is called implicitly when special syntax is used.

For example:

  • overloaded operators (exist in C ++, etc.)
  • Constructor / Destructor
  • attribute access bindings
  • metaprogramming tools

etc.

+54
Apr 17 '10 at 7:32
source share

From Zen Python:

In the face of ambiguity, give up the temptation to guess.
There should be one — and preferably only one — an easy way to do this.

This is one of the reasons - with the help of custom methods, developers could choose a different method name, for example getLength() , length() , getLength() or whatever. Python provides strict naming so that you can use the generic len() function.

All operations that are common to many types of objects are placed in magic methods, such as __nonzero__ , __len__ or __repr__ . They are mainly optional.

Operator overloading is also performed using magic methods (for example, __le__ ), so it makes sense to use them for other general operations.

+19
Apr 17 '10 at 7:37
source share

Python uses the word: - "Magic Methods" because these methods really do the magic for you. One of the biggest advantages of using Python magic methods is that they provide an easy way to make objects behave like built-in types. This means that you can avoid the ugly, anti-intuitive and non-standard ways to execute basic statements.

Consider the following example: -

 dict1 = {1 : "ABC"} dict2 = {2 : "EFG"} dict1 + dict2 Traceback (most recent call last): File "python", line 1, in <module> TypeError: unsupported operand type(s) for +: 'dict' and 'dict' 

This gives an error because the dictionary type does not support adding. Now let me extend the dictionary class and add the magic method "__ add __" : -

 class AddableDict(dict): def __add__(self, otherObj): self.update(otherObj) return AddableDict(self) dict1 = AddableDict({1 : "ABC"}) dict2 = AddableDict({2 : "EFG"}) print (dict1 + dict2) 

Now he gives the following conclusion,

 {1: 'ABC', 2: 'EFG'} 

Thus, adding this method, magic suddenly occurred and the error you received earlier is gone.

Hope this clarifies to you. For more information, see the link below: -

http://web.archive.org/web/20161024123835/http://www.rafekettler.com/magicmethods.html

+9
Sep 06 '16 at 3:42 on
source share

Some of these functions implement more than one method (without abstract methods on the superclass). For example, bool() acts something like this:

 def bool(obj): if hasattr(obj, '__nonzero__'): return bool(obj.__nonzero__()) elif hasattr(obj, '__len__'): if obj.__len__(): return True else: return False return True 

You can also be 100% sure that bool() will always return True or False; if you rely on a method, you cannot be completely sure what you would return.

Some other functions that have relatively complex implementations (more complex than the underlying magic methods are likely to be) are iter() and cmp() , and all attribute methods ( getattr , setattr and delattr ). Things like int also gain access to magic methods when forced (you can implement __int__ ), but perform double duties as types. len(obj) is actually the case when I do not believe that it has ever been different from obj.__len__() .

+7
Apr 17 '10 at 19:12
source share

They are not really “magic names”. This is just the interface that an object must implement to provide this service. In this sense, they are no more magical than any predefined interface definition that you must override.

+4
Apr 17 '10 at 8:53
source share

Although the reason is mostly historical, there are some features in Python len that make using a function instead of a suitable method.

Some operations in Python are implemented as methods, for example list.index and dict.append , while others are implemented as calling and magic methods, for example str and iter and reversed . These two groups differ from each other so much that a different approach is justified:

  • They are common.
  • str , int and friends are types. It makes sense to call the constructor.
  • The implementation is different from calling a function. For example, iter can call __getitem__ if __iter__ not available, and supports additional arguments that do not match the method call. For the same reason, it.next() been changed to next(it) in recent versions of Python - it makes sense.
  • Some of them are close relatives of the operators. There is syntax for calling __iter__ and __next__ - it called the for loop. For consistency, the function is better. And that makes it better for certain optimizations.
  • Some of the functions are just too similar to the others in some way - repr acts like str . str(x) vs x.repr() will be confused.
  • Some of them rarely use the actual implementation method, for example, isinstance .
  • Some of them are valid operators, getattr(x, 'a') is another way to make xa and getattr shares many of the above qualities.

I personally call the first group method, and the second - operator. This is not a very good difference, but I hope this helps in some way.

Having said that, len doesn't exactly match in the second group. This is closer to the operations in the first, with the only difference being that it is more common than almost any of them. But the only thing he does is call __len__ , and he is very close to L.index . However, there are some differences. For example, __len__ can be called to implement other functions, such as bool , if this method was called len , you can break bool(x) with the custom len method, which does a completely different thing.

In short, you have a set of very general functions that can be implemented by classes, which can be accessed through an operator, through a special function (which usually does more than an implementation, like an operator), when building an object, and they all have some common features . Everything else is a method. And len is a bit of an exception to this rule.

+1
Mar 05 2018-11-11T00:
source share

There is not much to add to these two posts, but all the “magic” functions are not really quite magical. They are part of the __ builtins__ module, which is implicitly / automatically imported when the interpreter starts. IE:

 from __builtins__ import * 

happens every time before running your program.

I always thought that it would be more correct if python did this only for the interactive shell and demanded that the scripts import the various parts from the built-in they need. It is also possible that another __ main__ processing would be nice in shells vs interactive. In any case, check all the functions and see what it is without them:

 dir (__builtins__) ... del __builtins__ 
0
Apr 19 '10 at 22:29
source share



All Articles