My goal is to check the similarity of an object using unittesting in python. I have this kind of object
class ImageModel(object):
def __init__(self):
self.data = data #this an array
self.name = name
self.path = path
I have read that if you want to do test the similarity of an array self.assertEqual(arr1,arr2) you have to put .all() after each array. But I have to check the similarity of an object which has an array within it. For my case, it would be:
self.assertEqual(ImageObj1, ImageObj2)
But it always show that those object isn't similar, i assume the problem is at the ImageObj.data
so, is there any way to assert equal an array within an object?
One possibility is to override the __eq__ method of your class. Basically, this is the method that is called when you're using the == operator on an ImageModel instance.
Here is an example:
def __eq__(self, other):
return (
# the two instances must be of the same class
isinstance(other, self.__class__) and
# compare name and path, that's straightforward
self.name == other.name and
self.path == other.path and
# and compare data
len(self.data) == len(other.data) and
all(a == b for a, b in zip(self.data, other.data))
)
Related
Is there ever a reason not to do this to compare two objects:
def __eq__(self, other):
return self.__dict__ == other.__dict__
as opposed to checking each individual attribute:
def __eq__(self, other):
return self.get_a() == other.get_a() and self.get_b() == other.get_b() and ...
Initially I had the latter, but figured the former was the cleaner solution.
You can be explicit and concise:
def __eq__(self, other):
fetcher = operator.attrgetter("a", "b", "c", "d")
try:
return self is other or fetcher(self) == fetcher(other)
except AttributeError:
return False
Just comparing the __dict__ attribute (which might not exist if __slots__ is used) leaves you open to the risk that an unexpected attribute exists on the object:
class A:
def __init__(self, a):
self.a = a
def __eq__(self, other):
return self.__dict__ == other.__dict__
a1 = A(5)
a2 = A(5)
a1.b = 3
assert a1 == a2 # Fails
Some comments:
You should include a self is other check, otherwise, under certain conditions, the same object in memory can compare unequal to itself. Here is a demonstration. The instance-check chrisz mentioned in the comments is a good idea as well.
The dicts of self and other probably contain many more items than the attributes you are manually checking for in the second version. Therefore, the first one will be slower.
(Lastly, but not related to the question, we don't write getters and setters in Python. Access attributes directly with the dot-notation, and if something special needs to happen when getting/setting an attribute, use a property.)
Having some trouble understanding why I'm able to re-define (monkey patch) __eq__ outside of a class, but not change its definition through __init__ or in a method:
class SpecialInteger:
def __init__(self,x):
self.x = x
self.__eq__ = self.equals_normal
def equals_normal(self,other):
return self.x == other.x
def equals_special(self,other):
return self.x != other.x
def switch_to_normal(self):
self.__eq__ = self.equals_normal
def switch_to_special(self):
self.__eq__ = self.equals_special
a = SpecialInteger(3)
b = SpecialInteger(3)
print(a == b) # false
a.switch_to_normal()
print(a == b) # false
SpecialInteger.__eq__ = SpecialInteger.equals_normal
print(a == b) # true
SpecialInteger.__eq__ = SpecialInteger.equals_special
print(a == b) # false
Am I just using self incorrectly or is there some other reason it works like this?
To do it inside the class, you would simply define the __eq__ method inside of your class.
class SpecialInteger:
def __init__(self,x):
self.x = x
def __eq__(self, other):
# do stuff, call whatever other methods you want
EDIT: I see what you are asking, you wish to override the method (which is a "magic" method) at the instance level. I don't believe this is possible in the base construct of the language, per this discussion.
The reason your monkey patch works in that example is because it is being passed on the Class level, as opposed to the instance level, whereas self is referring to the instance.
Just to add on to an excellent existing answer, but this doesn't work because you are modifying the class instance, and not the class.
In order to get the behavior you desire, you can modify the class during __init__, however, this is woefully inadequate (since it modifies the class, and therefore all instances of the class), and you are better off making those changes visible at the class scope.
For example, the following are equivalent:
class SpecialInteger1:
def __init__(self,x):
self.x = x
self.__class__.__eq__ = self.equals_normal
...
class SpecialInteger2:
def __init__(self,x):
self.x = x
def equals_normal(self,other):
return self.x == other.x
def __eq__(self, other):
return self.equals_normal(other)
You should prefer case SpecialInteger2 in all examples, since it is more explicit about what it does.
However, none of this actually solves the issue you are trying to solve: how can I create a specialized equality comparison at the instance level that I can toggle? The answer is through the use of an enum (in Python 3):
from enum import Enum
class Equality(Enum):
NORMAL = 1
SPECIAL = 2
class SpecialInteger:
def __init__(self, x, eq = Equality.NORMAL):
self.x = x
self.eq = eq
def equals_normal(self, other):
return self.x == other.x
def equals_special(self, other):
return self.x != other.x
def __eq__(self, other):
return self.__comp[self.eq](self, other)
# Define a dictionary for O(1) access
# to call the right method.
__comp = {
Equality.NORMAL: equals_normal,
Equality.SPECIAL: equals_special
}
Let's walk through this quickly, since there are 3 parts:
An instance member variable of eq, which can be modified dynamically.
An implementation of __eq__ that selects the correct equality function based on the value of self.eq.
A namespace-mangled dictionary (a class/member variable that starts with __, in this case, self.__comp) that allows efficient lookup of the desired equality method.
The dictionary can easily be done-away with, especially for cases where you only wish to support 1-5 different possible comparisons, and replaced with idiomatic if/then statements, however, if you ever wish to support many more comparison options (say, 300), a dictionary will be much more efficient O(1) than if/then comparisons (linear search, O(n)).
If you wish to do this with setters (like in the original example), and actually hide the member functions from the user, you can also do this by directly storing the function as a variable.
All method definitions are defined at class level (literally the name is a key in a dict belonging to the class). This is also true of anything else you put at class level. Which is why for instance a variable assignment outside a method in a class produces a class variable.
The easiest way to keep the same functionality would be to just refer to some other variable from __eq__. It could be some reference variable, or a saved method.
class SpecialInteger:
def __init__(self,x):
self.x = x
self._equal_method = self.equals_normal
# ...
def switch_to_normal(self):
self._equal_method = self.equals_normal
def switch_to_special(self):
self._equal_method = self.equals_special
def __eq__(self, other):
return self._equal_method(other)
Following the instructions here I created a subclass of ndarray that adds new attributes to the ndarray class. Now I want to define a comparison operator for the new class that besides comparing the data, also compares the values of the attributes. So I tried this:
def __eq__(self, other):
return (self._prop1 == other._prop1) and \
(self._prop2 == other._prop2) and \
(self.data == other.data)
This allows for comparison like T1 == T2 and returns a boolean value. However since I would like to use these arrays interchangeably with other ndarrays I would like the comparison to return a boolean array. If I don't define my __eq__ function then the comparison returns a boolean array, but then I can't check for the attributes. How can I combine the two?
As per the suggestion by hpaulj I figured out how to do this by looking at np.ma.core.MaskedArray.__eq__. Here's the minimum implementation for reference. The main idea is to call the numpy __eq__() on a view of self in the type of the base class of DerivedArray.
class DerivedArray(np.ndarray):
def __new__(cls, input_array, prop1, prop2):
_baseclass = getattr(input_array, '_baseclass', type(input_array))
obj = np.asarray(input_array).view(cls)
obj._prop1 = prop1
obj._prop2 = prop2
obj._baseclass = _baseclass
return obj
def __array_finalize__(self, obj):
if obj is None:
return
else:
if not isinstance(obj, np.ndarray):
_baseclass = type(obj)
else:
_baseclass = np.ndarray
self._prop1 = getattr(obj, '_prop1', None)
self._prop2 = getattr(obj, '_prop2', None)
self._baseclass= getattr(obj, '_baseclass', _baseclass)
def _get_data(self):
"""Return the current data, as a view of the original
underlying data.
"""
return np.ndarray.view(self, self._baseclass)
_data = property(fget=_get_data)
data = property(fget=_get_data)
def __eq__(self, other):
attsame = (self._prop1 == other._prop1) and (self._prop2 == other._prop2)
if not attsame: return False
return self._data.__eq__(other)
I have a custom class of objects with an assortment of various attributes of different types. I would like to remove duplicates from a list of these objects based on one of these attributes.
Something like this, but actually get a list of the objects rather than a list of the specified attribute.
filteredData = list(set([x.attribute[0] for x in objList]))
You need realize methods hash and eq on object
class A:
def __init__(self, a):
self.attr1 = a
def __hash__(self):
return hash(self.attr1)
def __eq__(self, other):
return self.attr1 == other.attr1
def __repr__(self):
return str(self.attr1)
Example:
l = [A(5), A(4), A(4)]
print list(set(l))
print list(set(l))[0].__class__ # ==> __main__.A. It's a object of class
This is the code I written so far, and the point with the program is to read 20 people from a file and then assign them their attributes, then normalise their values from a input given by the user.
class One:
def __init__(self):
self.attrOne = ()
self.attrTwo = ()
self.attrThree = ()
self.attrFour = ()
self.attrFive= ()
self.attrSix = ()
self.attrSeven = ()
self.attrEight = ()
self.attrNine = ()
class Two:
def __init__(self):
self.allPersons = []
def importFromList(self, filename):
file= open(filename, "rU")
for line in file:
partOfList = line.split()
x = Partner()
x.attrOne = partOfList[0]
x.attrTwo = partOfList[1]
x.attrThree = partOfList[2]
x.attrFour = partOfList[3]
x.attrFive = partOfList[4]
x.attrSix = partOfList[5]
x.attrSeven = partOfList[6]
x.attrEight= partOfList[7]
x.attrNine = partOfList[8]
self.addPerson(x)
file.close()
def addPerson(self, x):
self.allPersons.append(x)
What I wonder is how to loop through the attributes of the persons that is placed in allPersons list and then compare them against eachother to find out the max value. This is what I tried so far, but I can't get it to work
def getMaxValue(self):
o = One()
for eachPartner in self.allPartners:
maxValuesAttrOne = max(O.attrOne))
All help will be appreciated, and I'm open for new solutions, also I imagine the importFromList method is not the most effective one, so if you got any objections I'm willing to listen and learn!
max() takes a key parameter, a function that when passed one of the objects returns the value by which to compare them.
Use operator.attrgetter() to get that value:
from operator import attrgetter
max(self.allPartners, key=attrgetter('attrOne'))
This returns the matching object for which that attribute is the maximum. If you wanted to store just that maximum value itself, you have two options:
Take the attribute from the returned object:
max(self.allPartners, key=attrgetter('attrOne')).attrOne
Pass just the attributes instead to max() with a generator expression:
max(p.attrOne for p in self.allPartners)
If you find that you need to order the One classes in various directions by the same attribute again and again (to find the minimum, maximum, sort them, etc.) you may want to make your class orderable as well.
To do that, you'll need to implement some of the basic customization hooks Python will look for. With some extra trickery, you can get away with just the lower-than and equals operations, and by using the funtools.total_ordering class decorator:
from functools import total_ordering
#total_ordering
class One:
# ...
def __lt__(self, other):
if not isinstance(other, type(self)): return NotImplemented
return self.attrOne < other.attrOne
def __eq__(self, other):
if not isinstance(other, type(self)): return NotImplemented
return self.attrOne == other.attrOne
Now your One class is orderable, entirely on the basis of attrOne; for the max() function, that means you can drop the key parameter altogether.