There is a difference between the methods (without dunders) and the dunders methods.
Example:Operator.setitem(a, b, c) and operator.__setitem__(a, b, c)
?
There’s probably no difference - (as in the other answer, they’re just aliases).
The recommendation however is: let the language call internally the names with "Dunder", and, when making explicit calls, always use the name without Dunder - when there is.
As we have seen some of the Operator module methods make calls to internal object methods if it has been defined. But
I honestly don’t know why, I’m led to believe that when we do
an operation for example of sum, is somehow invoked
Operator.add(or operator.__add__
), am I wrong?
in fact, it is the opposite - in Python, each class defines how objects will behave with operators - that is, the language allows "Operator Overriding". The way this is done by language is described in the document called Data Model in language documentation. . In short - the Dunder methods in class is that contains the code that will be executed when instances of that class are involved with the use of operators, or other actions involving the "Dunder methods".
It is easy to see that the flow is this when trying to imagine the opposite: if the "specific code" for the add of each class was in the "power" of operator.add
, and not in every class, where developers would put the code to the operator operator.add
use? Or even thinking about the existing code - would it make sense to operator.add
centralize both the code for the addition of sequences (which is concatenation) and numbers (addition)?
So the path is the opposite - the module operator
is a "nice to have", but by no means essential in any Python program.
In practice, it is just a way of maintaining the rule - more of style than necessity - of "you don’t need to call the 'Dunder' methods directly". So you can write operator.neg(b)
instead of b.__neg__()
. (For binary operators, the functions in Operator do a little more - why they also implement the logic of calling the reverse sum - __radd__
, in the second object of an operation, if the sum between the object types of the expression is not implemented in the first object).
So much so that it contains the mathematical operators and others with proper syntax in the language - whose most common use is in expressions that get fixed in the program (that is - it is more common for you to write a = b + c
than a = add(b, c)
). However, some Dunder methods that do not have special syntax have the call equivalent to those in the module operator
direct as built-in language - for example, the functions len
and hash
which call respectively the methods __len__
and __hash__
One of the uses that module operator
has is when, at the time you write a type of code, you don’t know yet what operation will be executed between two operands - for example, a calculator program can check whether the user has typed "-" or "+" to choose "Operator.add" or "Operator.sub" programmatically, more elegantly than a sequence of if
s where the expression is repeated every time:
Instead of:
if operacao == "+":
a = b + c
elif operacao == "-":
a = b - c
...
it is possible to write something like:
operacoes = {'+': operator.add, '-': operator.sub, ...}
a = operacores[operacao](b, c)
and that being said, some members of the "Operator" module still do something else - for example, the itemgetter
, attrgetter
and methodcaller
return a reusable calling object (which can be called as if it were a function), which can be used with several different objects in creating rather elegant code.
For those interested, module source code
operator
: https://github.com/python/cpython/blob/master/Lib/operator.py#L420– Woss