Python 2.7 - Define Basic Operators for Specific Classes [duplicate] - python

How do you go about overloading the addition, subtraction, and multiplication operator so we can add, subtract, and multiply two vectors of different or identical sizes? For example, if the vectors are different sizes we must be able to add, subtract, or multiply the two vectors according to the smallest vector size?
I've created a function that allows you to modify different vectors, but now I'm struggling to overload the operators and haven't a clue on where to begin. I will paste the code below. Any ideas?
def __add__(self, y):
self.vector = []
for j in range(len(self.vector)):
self.vector.append(self.vector[j] + y.self.vector[j])
return Vec[self.vector]

You define the __add__, __sub__, and __mul__ methods for the class, that's how. Each method takes two objects (the operands of +/-/*) as arguments and is expected to return the result of the computation.

Nothing wrong with the accepted answer on this question but I'm adding some quick snippets to illustrate how this can be used. (Note that you could also "overload" the method to handle multiple types.)
"""Return the difference of another Transaction object, or another
class object that also has the `val` property."""
class Transaction(object):
def __init__(self, val):
self.val = val
def __sub__(self, other):
return self.val - other.val
buy = Transaction(10.00)
sell = Transaction(7.00)
print(buy - sell)
# 3.0
"""Return a Transaction object with `val` as the difference of this
Transaction.val property and another object with a `val` property."""
class Transaction(object):
def __init__(self, val):
self.val = val
def __sub__(self, other):
return Transaction(self.val - other.val)
buy = Transaction(20.00)
sell = Transaction(5.00)
result = buy - sell
print(result.val)
# 15
"""Return difference of this Transaction.val property and an integer."""
class Transaction(object):
def __init__(self, val):
self.val = val
def __sub__(self, other):
return self.val - other
buy = Transaction(8.00)
print(buy - 6.00)
# 2

docs have the answer. Basically there are functions that get called on an object when you add or multiple, etc. for instance __add__ is the normal add function.

Related

How to combine two objects of the class together as a dictionary [duplicate]

How do you go about overloading the addition, subtraction, and multiplication operator so we can add, subtract, and multiply two vectors of different or identical sizes? For example, if the vectors are different sizes we must be able to add, subtract, or multiply the two vectors according to the smallest vector size?
I've created a function that allows you to modify different vectors, but now I'm struggling to overload the operators and haven't a clue on where to begin. I will paste the code below. Any ideas?
def __add__(self, y):
self.vector = []
for j in range(len(self.vector)):
self.vector.append(self.vector[j] + y.self.vector[j])
return Vec[self.vector]
You define the __add__, __sub__, and __mul__ methods for the class, that's how. Each method takes two objects (the operands of +/-/*) as arguments and is expected to return the result of the computation.
Nothing wrong with the accepted answer on this question but I'm adding some quick snippets to illustrate how this can be used. (Note that you could also "overload" the method to handle multiple types.)
"""Return the difference of another Transaction object, or another
class object that also has the `val` property."""
class Transaction(object):
def __init__(self, val):
self.val = val
def __sub__(self, other):
return self.val - other.val
buy = Transaction(10.00)
sell = Transaction(7.00)
print(buy - sell)
# 3.0
"""Return a Transaction object with `val` as the difference of this
Transaction.val property and another object with a `val` property."""
class Transaction(object):
def __init__(self, val):
self.val = val
def __sub__(self, other):
return Transaction(self.val - other.val)
buy = Transaction(20.00)
sell = Transaction(5.00)
result = buy - sell
print(result.val)
# 15
"""Return difference of this Transaction.val property and an integer."""
class Transaction(object):
def __init__(self, val):
self.val = val
def __sub__(self, other):
return self.val - other
buy = Transaction(8.00)
print(buy - 6.00)
# 2
docs have the answer. Basically there are functions that get called on an object when you add or multiple, etc. for instance __add__ is the normal add function.

How to subclass "float" without implementing its method?

I want to subclass from float but don't want it to init soon. I also don't want to explicitly call float() for my object.
For example, I don't want to calculate anything before it is required. I want only to do an object that behaves like float. Here is how I want to create class:
class MassiveAverage(float):
def __init__(self, floats: list[float]):
self.floats = floats
def __float__(self) -> float:
return sum(self.floats) / len(self.floats)
And this is how I want to use it:
massive_average = MassiveAverage([1.1, 2.2]) # no any calculations
massive_sum = massive_average * 2 # this is were it calculates its float value
For the answer to this question I am going to assume you are already familiar with python's "magic methods". #gftea's answer has a link to the documentation for some of the magic methods if you are not familiar.
You are going to have to manually define each "magic function" __mul__, __add__, __sub__, etc.
class MassiveAverage:
def __init__(self, floats):
self._avg = sum(floats)/len(floats)
def __mul__(self, other):
return self._avg * other
def __sub__(self, other):
return self._avg - other
def __add__(self, other):
return self._avg + other
...
But, this doesn't handle your lazy evaluation use case. Instead, we could maintain an internal cache, and on the first time one of these magic methods are evaluated, we could run the average function.
class MassiveAverage:
def __init__(self, floats):
self._floats = floats
self._avg = None
#property
def avg(self):
if self._avg is None:
self._avg = sum(self._floats) / len(self._floats)
return self._avg
Then, we can replace our magic functions and use self.avg.
def __mul__(self, other):
return self.avg * other
def __add__(self, other):
return self.avg + other
def __sub__(self, other):
return self.avg - other
...
Unfortunately, you cannot subclass float in the manner you want. Because you are specifying lazy evaluation, you are fundamentally changing how the methods in the float class work (since they don't need lazy evaluation). You would still have to manually change each magic method.
you should overwrite the operator, for example, to overwrite *, you can overwrite the __mul__ method
def __mul__(self, float): ...
see below for methods can be defined to emulate numeric objects
https://docs.python.org/3/reference/datamodel.html?highlight=rmul#emulating-numeric-types
__float__ is used for exactly one purpose: to define the behavior of float(x) as x.__float__(). There is no implicit conversion in an expression like massive_average * 2. This could mean any number of things:
massive_average.__int__() * 2
massive_average.__float__() * 2
massive_average.__complex__() * 2
massive_avarge.__str__() * 2
so Python refuses to guess. It will try massive_average.__mul__(2), and failing that, (2).__rmul__(massive_average), before giving up.
Each of the type-specific "conversion" methods are used only by the corresponding type itself. print, for example, does not call __str__ (directly); it only is defined to call str on each of its arguments, and str takes care of calling __str__.

How do I add/modify methods to built-in objects? [duplicate]

I'm currently learning python operator overloading (__radd__ and __add__ to be exact) and I have the following code
class Commuter1:
def __init__(self, val):
self.val = val
def __add__(self, other):
print('add', self.val, other)
return self.val + other
def __radd__(self, other):
print('radd', self.val, other)
return other + self.val
x = Commuter1(88)
y = Commuter1(99)
print(x + y)
I have got the following result
When used separately, I understand how __radd__ and __add__ works. But for the line x + y, I'm not sure why both __radd__ and __add__ methods are evoked.
First, Python looks at the types of x and y to decide whether to call x.__add__ or y.__radd__. Since they're both the same type Commuter1, it tries x.__add__ first.
Then, inside your __add__ method, you do this:
return self.val + other
So, Python looks at the types of self.val and other to decide whether to call self.val.__add__ or other.__radd__. Since they're unrelated types int and Commuter1, it tries int.__add__ first.
But int.__add__ returns NotImplemented for a type it doesn't know about, so Python falls back to calling other.__radd__.
Inside your __radd__ method, you do this:
return other + self.val
So, Python looks at the types of other and self.val to decide whether to call other.__add__ or self.val.__radd__. Since they both the same type int, it tries __add__ first.
And of course int.__add__ works on another int, so it returns a value for the inner + inside your __radd__, which you return, which returns a value for the + inside __add__, which you return, which returns a value for the top-level +, which you print.

comparing two list with custom objects, not behaving as I expect (Lexicography comparison) - Python

I have two Python lists.
a = [A(1), B(1)]
b = [A(1), B(2)]
The check a < b does not get to call B's __lt__ operator. The conclusion is that a is not smaller than b.
I have verified that A's __lt__ is called (actually twice to see if the first element in a is smaller than the one in b, and then the other way around).
Thanks in advance,
Oren
When you compare two lists in Python, it compares them element-by-element and stops comparing them after finding two unequal elements. This doesn't mean that one element has to be greater or less than the other, just that they have to be unequal. Here's a naive example using something that I think is similar to what you have; consider a class A:
class A:
def __init__(self, val):
self.val = val
def __lt__(self, obj):
return self.val < obj.val
Now consider two objects a and b such that a = A(1) and b = A(1). a < b evaluates to False like we'd expect, but a == b also evaluates to False. This is because the object has no way to compare equality through an __eq__ method, and the objects are not the exact same instance. We can add one like so:
def __eq__(self, obj):
return self.val == obj.val
Now, a == b will evaluate to True and your original expression will work as expected.
Python will only compare the second items if the first items were found to be equal. If the second items are not being compared this implies the first items were not equal.
So the issue likely lies with the __lt__ implementation for A, if you want to post that code we might be able to help spot the issue.
the python documentation clearly states that lt gets called on the first object that is not equal. In your example you did not mention you inplemented the eq operator, so this is my reproduction:
class A:
def __init__(self, val):
self.val = val
def __lt__(self, other):
print('lt in A')
return self.val < other.val
class B:
def __init__(self, val):
self.val = val
def __lt__(self, other):
print('lt in B')
return self.val < other.val
a = [A(1), B(2)]
b = [A(1), B(1)]
print(a < b)
which outputs:
lt in A
False
because the first object is different (although the same val) and it will take the result of that lt
when you implement the __eq__ method, it will continue to do this:
class A:
def init(self, val):
self.val = val
def __lt__(self, other):
print('lt in A')
return self.val < other.val
def __eq__(self, other):
return self.val == other.val
will output
lt in B
True
because the first element evaluates to true using eq

Creating array of unique objects in Python

Let's suppose I have a program that creates some scheme with lines and points.
All lines determine by two points. There are these classes:
class Coordinates(object):
def __init__(self, x, y):
self.x = x
self.y = y
class Point(object):
def __init__(self, coordinates):
self.coordinates = coordinates
class Line(object):
def __init__(self, coordinates_1, coordinates_2):
self.coordinates_1 = coordinates_1
self.coordinates_2 = coordinates_2
A scheme takes list of lines and creates a list of unique points.
class Circuit(object):
def __init__(self, element_list):
self.line_list = element_list
self.point_collection = set()
self.point_collection = self.generate_points()
def generate_points(self):
for line in self.line_list:
coordinates_pair = [line.coordinates_1, line.coordinates_2]
for coordinates in coordinates_pair:
self.point_collection.add(Point(coordinates))
return self.point_collection
What variants are able to make a list or collection of unique objects? How to do it without using sets and sorting, only with loops and conditions? And how to do it simplier?
UPD. Code I attached doesn't work properly. I tried to add hash and eq methods in Point class:
class Point(object):
def __init__(self, coordinates):
self.coordinates = coordinates
def __hash__(self):
return 0
def __eq__(self, other):
return True
Then I try to make a scheme with some lines:
element_list=[]
element_list.append(Line(Coordinates(0,0), Coordinates(10,0)))
element_list.append(Line(Coordinates(10,0), Coordinates(10,20)))
circuit = Circuit(element_list)
print(circuit.point_collection)
Two lines here equal four points, where two points have the same coordinates. Hence, the code must print three objects, but it does only one:
{<__main__.Point object at 0x0083E050>}
Short answer:
You need to implement __hash__() and __eq__() methods in your Point class.
For an idea, see this answer showing a correct and good way to implement __hash__().
Long answer:
The documentation says that:
A set object is an unordered collection of distinct hashable objects. Common uses include (...) removing duplicates from a sequence (...)
And hashable means:
An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() method). Hashable objects which compare equal must have the same hash value.
Objects which are instances of user-defined classes are hashable by default; they all compare unequal (except with themselves), and their hash value is derived from their id().
Which explains why your code does not remove duplicate points.
Consider this implementation that makes all instances of Foo distinct and all instances of Bar equal:
class Foo:
pass
class Bar:
def __hash__(self):
return 0
def __eq__(self, other):
return True
Now run:
>>> set([Foo(), Foo()])
{<__main__.Foo at 0x7fb140791da0>, <__main__.Foo at 0x7fb140791f60>}
>>> set([Bar(), Bar()])
{<__main__.Bar at 0x7fb1407c5780>}
In your case, __eq__ should return True when both coordinates are equal, while __hash__ should return a hash of the coordinate pair. See the answer mentioned earlier for a good way to do this.
Some remarks:
Your Point class has currently no reason to exist from a design perspective, since it is just a wrapper around Coordinates and offers no additional functionality. You should just use either one of them, for example:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
And why not call coordinates_1 and coordinates_2 just a and b?
class Line(object):
def __init__(self, a, b):
self.a = a
self.b = b
Also, your generate_points could be implemented in a more pythonic way:
def generate_points(self):
return set(p for l in self.line_list for p in (l.a, l.b))
Finally, for easier debugging, your might consider implementing __repr__ and __str__ methods in your classes.

Categories