how to make an operator function in python? - python

I need to make an operators to an object and I wonder what is the best way.
for example for the operator add
can I write this in this way?
def _add_(self,other):
new=self.add(self,other)// can I write like that?
return new
thanks for the help!

You would use the python magic function __add__ to take care of the +:
Example:
class A():
def __init__(self, num):
self.num = num
def __add__(self, other):
return self.num + other
a = A(6)
>>> print a+5
11
For greater flexibility, you should also define __radd__, this is for the reverse addition case 5+a which would not work in the example above.
class A():
def __init__(self, num):
self.num = num
def __add__(self, other):
return self.num + other
def __radd__(self, other):
return self.num + other
>>> a = A(6)
>>> print 5+a
11
>>> print a+5
11
Or if you want to return as an object instead of an int, you can do it as:
class A():
def __init__(self, num):
self.num = num
def __add__(self, other):
return A(self.num + other)
a = A(5)
b = a+5
print b.num
10
print a.num
5
What has been demonstrated above is operator overloading. It overrides the built-in default methods for handling operators by letting the user define custom methods for the operators.
Here is a list you might find useful as to which operators can be overloaded

Related

I want to give an input of adding two numbers but it should return multiplication of those two numbers using operator overloading

I am a newbie. I want to use operator overloading which gives 3+4 but returns answer of 3*4
I have made a class and passed two functions add and mul
class A:
def __init__(self, a,b):
self.a = a
self.b = b
# adding two objects
def __add__(self, other):
return self.a + other.a , self.b + other.b
# multiply two objects
def __mul__(self, other):
return self.a * other.a , self.b +other.b
ob1 = A(1)
ob2 = A(2)
ob3 = ob1+ob2
ob4 = ob1*ob2
print(ob3)
print(ob4)
Expected: input 3 and 4 , it should show 3+4 but return 3*4
In your __mul__ and __add__ methods, you need to return an instance of A, not just some values (unless you are doing in place operations). It seems like you only want to add 2 numbers together, so maybe you should try having only 1 parameter __init__:
class A:
def __init__(self, a):
self.a = a
def __add__(self, other):
return A(self.a * other.a)
Now when you do:
A(3) + A(2)
You are getting back 2*3 as the __add__ method returns a new instance of A whose .a attribute is the product, not sum, of the given two.
You should also consider type checking or error handling as your next step. What if I typed:
A(2) + 10 # not A(10)
Would an error be raised? That’s up to you. The easiest way to cause an error to be raised if you return NotImplemented from the function. This method also allows polymorphism to take place where any object with a .a attribute will work (as long as it is something that can be multiplied).
...
def __add__(self, other):
try:
return A(self.a * other.a)
except Exception:
return NotImplemented

How can I override magic methods?

Today, I was reading a book about python and I got to know that there are some magic methods such as __add__ and __mul__.
But, in the book, there is no explanation on how to use them.
So, I tried to figure it out by myself. But, I couldn't figure out how to override magic methods.
Here is the code I tried.
>>> class Num(int):
... def __init__(self, number):
... self.number = number
... def __add__(self, other):
... self.number += other*100
... return self.number
...
>>> num = Num(10)
>>> num.number + 10
20
Could anyone please help me understand how these magic methods work?
In [12]: class Num(int):
...: def __init__(self, number):
...: self.number = number
...: def __add__(self, other):
...: #self.number += other*100 #why do you want to do other*100?
...: return Num(self.number+
...: Num(other).number) #wrap "other" with "Num"
#in case "other" is an "int"
In [13]: num = Num(10)
...: print num+10
20
Actually, you don't need to override __add__ if your Num is a subclass of int. Simply call super in __init__ would suffice:
In [19]: class Num(int):
...: def __init__(self, *args):
...: super(Num, self).__init__(args)
In [20]: Num(10)
Out[20]: 10
In [21]: Num(10)+10
Out[21]: 20
and this way no other attribute like self.number is needed.
class Num:
def __init__(self, number):
self.number = number
def __add__(self, other):
self.number += other*100
>> num = Num(10)
>> num.number
10
>> num + 10 # note that you are adding to num, not to num.number
>> num.number
1010
That's how overriding __add__ works. Version with return:
class Num:
def __init__(self, number):
self.number = number
def __add__(self, other):
return self.number + other*100
>> num = Num(10)
>> num.number
10
>> num + 10 # again adding to num
1010
>> num.number
10
So basically when Python sees
x + y
x += y
x * y
x *= y
etc
it translates it to
x.__add__(y)
x.__iadd__(y)
x.__mul__(y)
x.__imul__(y)
etc
You are wanting to override the method of your class and not of one specific property.
In your implementation, num.number + 10 will not trigger your class __add__ method but rather the method of the variable you are operating on - in your case, an int.
num.number.__add__
This is why you see the output of 20 - it uses the default __add__ 10 + 10 = 20
If you want to use the method of your class, you would do it like this:
num = Num(10)
num + 10
Now you are accessing your num.__add__ method.

What is the "metaclass" way to do this?

I want to write a program that accepts as input a number p and produces as output a type-constructor for a number that obeys integer arithmetic modulo p.
So far I have
def IntegersModP(p):
N = type('IntegersMod%d' % p, (), {})
def __init__(self, x): self.val = x % p
def __add__(a, b): return N(a.val + b.val)
... (more functions) ...
attrs = {'__init__': __init__, '__add__': __add__, ... }
for name, f in attrs.items():
setattr(N, name, f)
return N
This works fine, but I'd like to know what the Pythonic way to do this is, which I understand would use metaclasses.
Like this:
def IntegerModP(p): # class factory function
class IntegerModP(object):
def __init__(self, x):
self.val = x % p
def __add__(a, b):
return IntegerModP(a.val + b.val)
def __str__(self):
return str(self.val)
def __repr__(self):
return '{}({})'.format(self.__class__.__name__, self.val)
IntegerModP.__name__ = 'IntegerMod%s' % p # rename created class
return IntegerModP
IntegerMod4 = IntegerModP(4)
i = IntegerMod4(3)
j = IntegerMod4(2)
print i + j # 1
print repr(i + j) # IntegerMod4(1)
Metaclasses are for when your class needs to behave differently from a normal class or when you want to alter the behavior of the class statement. Neither of those apply here, so there's really no need to use a metaclass. In fact, you could just have one ModularInteger class with instances that record their value and modulus, but assuming you don't want to do that, it's still easy to do this with an ordinary class statement:
def integers_mod_p(p):
class IntegerModP(object):
def __init__(self, n):
self.n = n % IntegerModP.p
def typecheck(self, other):
try:
if self.p != other.p:
raise TypeError
except AttributeError:
raise TypeError
def __add__(self, other):
self.typecheck(other)
return IntegerModP(self.n + other.n)
def __sub__(self, other):
...
IntegerModP.p = p
IntegerModP.__name__ = 'IntegerMod{}'.format(p)
return IntegerModP

Comparison of hashable objects

I have a tuple of python objects, from which I need a list of objects with no duplicates, using set() (this check for duplicate objects is to be done on an attribute.). This code will give a simple illustration:
class test:
def __init__(self, t):
self.t = t
def __repr__(self):
return repr(self.t)
def __hash__(self):
return self.t
l = (test(1), test(2), test(-1), test(1), test(3), test(2))
print l
print set(l)
However, it did not work. I can do it on an iteration over l, but any idea why set() is not working? Here is the official documentation.
From the documentation you linked to:
The set classes are implemented using dictionaries. Accordingly, the
requirements for set elements are the same as those for dictionary
keys; namely, that the element defines both __eq__() and __hash__().
To be more specific, if a == b then your implementation must be such that hash(a) == hash(b). The reverse is not required.
Also, you should probably call hash in __hash__ to handle long integers
class Test:
def __init__(self, t):
self.t = t
def __repr__(self):
return repr(self.t)
def __hash__(self):
return hash(self.t)
def __eq__(self, other):
return isinstance(other, Test) and self.t == other.t
Small nit picks:
Your implementation of __eq__ doesn't give the other object a chance to run its own __eq__. The class must also consider its members as immutable as the hash must stay constant. You don't want to break your dicts, do you?
class Test:
def __init__(self, t):
self._t = t
#property
def t(self):
return self._t
def __repr__(self):
return repr(self._t)
def __hash__(self):
return hash(self._t)
def __eq__(self, other):
if not isinstance(other, Test):
return NotImplemented # don't know how to handle `other`
return self.t == other.t

Decorating arithmetic operators | should I be using a metaclass?

I'd like to implement an object, that bounds values within a given range after arithmetic operations have been applied to it. The code below works fine, but I'm pointlessly rewriting the methods. Surely there's a more elegant way of doing this. Is a metaclass the way to go?
def check_range(_operator):
def decorator1(instance,_val):
value = _operator(instance,_val)
if value > instance._upperbound:
value = instance._upperbound
if value < instance._lowerbound:
value = instance._lowerbound
instance.value = value
return Range(value, instance._lowerbound, instance._upperbound)
return decorator1
class Range(object):
'''
however you add, multiply or divide, it will always stay within boundaries
'''
def __init__(self, value, lowerbound, upperbound):
'''
#param lowerbound:
#param upperbound:
'''
self._lowerbound = lowerbound
self._upperbound = upperbound
self.value = value
def init(self):
'''
set a random value within bounds
'''
self.value = random.uniform(self._lowerbound, self._upperbound)
def __str__(self):
return self.__repr__()
def __repr__(self):
return "<Range: %s>" % (self.value)
#check_range
def __mul__(self, other):
return self.value * other
#check_range
def __div__(self, other):
return self.value / float(other)
def __truediv__(self, other):
return self.div(other)
#check_range
def __add__(self, other):
return self.value + other
#check_range
def __sub__(self, other):
return self.value - other
It is possible to use a metaclass to apply a decorator to a set of function names, but I don't think that this is the way to go in your case. Applying the decorator in the class body on a function-by-function basis as you've done, with the #decorator syntax, I think is a very good option. (I think you've got a bug in your decorator, BTW: you probably do not want to set instance.value to anything; arithmetic operators usually don't mutate their operands).
Another approach I might use in your situation, kind of avoiding decorators all together, is to do something like this:
import operator
class Range(object):
def __init__(self, value, lowerbound, upperbound):
self._lowerbound = lowerbound
self._upperbound = upperbound
self.value = value
def __repr__(self):
return "<Range: %s>" % (self.value)
def _from_value(self, val):
val = max(min(val, self._upperbound), self._lowerbound)
# NOTE: it's nice to use type(self) instead of writing the class
# name explicitly; it then continues to work if you change the
# class name, or use a subclass
return type(self)(val, rng._lowerbound, rng._upperbound)
def _make_binary_method(fn):
# this is NOT a method, just a helper function that is used
# while the class body is being evaluated
def bin_op(self, other):
return self._from_value(fn(self.value, other))
return bin_op
__mul__ = _make_binary_method(operator.mul)
__div__ = _make_binary_method(operator.truediv)
__truediv__ = __div__
__add__ = _make_binary_method(operator.add)
__sub__ = _make_binary_method(operator.sub)
rng = Range(7, 0, 10)
print rng + 5
print rng * 50
print rng - 10
print rng / 100
printing
<Range: 10>
<Range: 10>
<Range: 0>
<Range: 0.07>
I suggest that you do NOT use a metaclass in this circumstance, but here is one way you could. Metaclasses are a useful tool, and if you're interested, it's nice to understand how to use them for when you really need them.
def check_range(fn):
def wrapper(self, other):
value = fn(self, other)
value = max(min(value, self._upperbound), self._lowerbound)
return type(self)(value, self._lowerbound, self._upperbound)
return wrapper
class ApplyDecoratorsType(type):
def __init__(cls, name, bases, attrs):
for decorator, names in attrs.get('_auto_decorate', ()):
for name in names:
fn = attrs.get(name, None)
if fn is not None:
setattr(cls, name, decorator(fn))
class Range(object):
__metaclass__ = ApplyDecoratorsType
_auto_decorate = (
(check_range,
'__mul__ __div__ __truediv__ __add__ __sub__'.split()),
)
def __init__(self, value, lowerbound, upperbound):
self._lowerbound = lowerbound
self._upperbound = upperbound
self.value = value
def __repr__(self):
return "<Range: %s>" % (self.value)
def __mul__(self, other):
return self.value * other
def __div__(self, other):
return self.value / float(other)
def __truediv__(self, other):
return self / other
def __add__(self, other):
return self.value + other
def __sub__(self, other):
return self.value - other
As it is wisely said about metaclasses: if you wonder wether you need them, then you don't.
I don't fully understand your problem, but I would create a BoundedValue class, and us only instances of said class into the class you are proposing.
class BoundedValue(object):
default_lower = 0
default_upper = 1
def __init__(self, upper=None, lower=None):
self.upper = upper or BoundedValue.default_upper
self.lower = lower or BoundedValue.default_lower
#property
def val(self):
return self._val
#val.setter
def val(self, value):
assert self.lower <= value <= self.upper
self._val = value
v = BoundedValue()
v.val = 0.5 # Correctly assigns the value 0.5
print v.val # prints 0.5
v.val = 10 # Throws assertion error
Of course you could (and should) change the assertion for the actual behavior you are looking for; also you can change the constructor to include the initialization value. I chose to make it an assignment post-construction via the property val.
Once you have this object, you can create your classes and use BoundedValue instances, instead of floats or ints.

Categories