Monkey patching __eq__ in Python - python

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)

Related

Maintaining staticmethod calls if class is renamed

I have a class with a static method which is called multiple times by other methods. For example:
class A:
def __init__(self):
return
#staticmethod
def one():
return 1
def two(self):
return 2 * A.one()
def three(self):
return 3 * A.one()
Method one is a utility function that belongs inside the class but isn't logically an attribute of the class or the class instance.
If the name of the class were to be changed from A to B, do I have to explicitly change every call to method one from A.one() to B.one()? Is there a better way of doing this?
I pondered this question once upon a time and, while I agree that using a refactoring utility is probably the best way to go, as far as I can tell it is technically possible to achieve this behaviour in two ways:
Declare the method a classmethod.
Use the __class__ attribute. Leads to rather messy code, and may well be deemed unsafe or inefficient for reasons I am not aware of(?).
class A:
def __init__(self):
return
#staticmethod
def one():
return 1
#classmethod
def two(cls):
return 2 * cls.one()
def three(self):
return 3 * self.__class__.one()
a = A()
print(a.two())
print(a.three())

Comparing two objects using __dict__

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.)

'Reversed' comparison operator in Python

class Inner():
def __init__(self, x):
self.x = x
def __eq__(self, other):
if isinstance(other, Inner):
return self.x == other.x
else:
raise TypeError("Incorrect type to compare")
class Outer():
def __init__(self, y):
self.y = Inner(y)
def __eq__(self, other):
if isinstance(other, Outer):
return self.y == other.y
elif isinstance(other, Inner):
return self.y == other
else:
raise TypeError("Incorrect type to compare")
if __name__ == "__main__":
a = Outer(1)
b = Inner(1)
print(a == b) # ok no problem
print(b == a) # This will raise a type error
In the example I have inner and outer class. I have no control over what Inner implements just wanted to simulate the situation. I have only control over Outer's behavior. I want Outer instances to be able to compare to Inner instances (not just equality). With the given implementation only the first comparison works because that is calling Outer's __eq__ method allowed to be compared to Outer and Inner instances but the second one is calling Inner's __eq__ which will not allow the comparison to Outer - heck it doesn't know Outer exists why should it bother to implement it.
Is there a way to get the second type of comparison to work, with something similar like the __radd__ and such functions.
I know for instance in C++ you resolve this with inline operator definitions, but we don't have such in Python.
Not to put too fine a point on it: Inner.__eq__ is broken. At the very least, rather than throwing an error it should return NotImplemented, which would allow Python to try the reverse comparison:
When NotImplemented is returned, the interpreter will then try the
reflected operation on the other type, or some other fallback,
depending on the operator. If all attempted operations return
NotImplemented, the interpreter will raise an appropriate exception.
Better yet it would use "duck typing", rather than insisting on a specific class (unless the class, rather than its interface, is an explicitly important part of the comparison):
def __eq__(self, other):
try:
return self.x == other.x
except AttributeError:
return NotImplemented
However, as you say you cannot control this, you will have to manually implement similar functionality, for example:
def compare(a, b):
"""'Safe' comparison between two objects."""
try:
return a == b
except TypeError:
return b == a
as there is no such thing as __req__ in Python's data model.

Python 3: Calling a class function inside of __init__

I have a little question about python 3.
I want to create a class, which is using a function from within of that class. Just like:
class Plus:
def __init__(self, x, y):
self.x = x
self.y = y
self.test()
def test(self):
return self.x + self.y
now I am doing something like
a = Plus(5,6)
print(a)
and python is giving me
<__main__.Plus object at 0x000000000295F748>
and not 11 as I want it. I know that I can get 11 by
a = Plus(5, 6).test()
print(a)
but that's not what I want. I want to call the class and getting the result without adding .test() to it.
Can you help me?
I would go for:
class Plus:
def __init__(self, x, y):
self.x = x
self.y = y
self.test()
def test(self):
res = self.x + self.y
self.__repr__ = lambda:str(res)
return res
>>> Plus(5,5)
10
>>> a = Plus(5,5)
>>> a
10
>>> a.test()
10
This way you are not recomputing the sum each time you call print, its updated when you call the test method.
You'd need to define a __str__ method for your Plus class:
class Plus:
def __init__(self, x, y):
self.x = x
self.y = y
def test(self):
return self.x + self.y
def __str__(self):
return str(self.test())
now I am doing something like
a = Plus(5,6)
print(a)
and python is giving me
<__main__.Plus object at 0x000000000295F748>
and not 11 as I want it. I know that I can get 11 by
a = Plus(5, 6).test()
print(a)
but that's not what I want. I want to call the class and getting the result without adding .test() to it.
I am not sure what do you mean by 'and not 11 as I want it'. If you want Plus(5, 6) to actually return 11 (int instance), you should make Plus a function that returns the sum. Alternatively you can override __new__ method and hook upon object creation -- but this is a bad idea.
What are you trying to achieve?
I doubt, that by 'and not 11 as I want it' you want something special to be printed (formatted, represented). If so, override __str__ or __unicode__ or __repr__ method.
Edit:
ignore this answer, it is a comment on a misinterpretation of the question
This is just wrong.
when you instantiate an object, you'd expect to get a reference to that object.
if you just want a global function returning a number, why even bother to make a class with an init?
in python you shouldn't want static class's like in C# for encapsulation. instead name the module something, and use that for encapsulation.

Is there a way to run a method for all instances of a class in python?

Example code:
>>> class MyClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
def power(self):
print(self.x**self.y)
def divide(self):
print(self.x/self.y)
>>> foo = MyClass(2, 3)
>>> bar = MyClass(4, 7)
>>>
>>> foo.power()
8
>>> bar.divide()
0.5714285714285714
Whenever I used classes in Python previously, I just ran the method for each instance separately (see above). I was just wondering If there was a way to run the same method for all the instances of that class at once, because it could get a bit annoying, if you have 20 or so instances. I'm thinking of something like this:
>>> allinstances.power()
8
16384
Is there a way of doing this?
class MyClass(object):
instancelist = []
def __init__(self, x, y):
self.x = x
self.y = y
MyClass.instancelist.append(self)
def power(self):
print(self.x ** self.y)
def divide(self):
print(self.x / self.y)
foo = MyClass(2, 3)
bar = MyClass(4, 7)
[instance.power() for instance in MyClass.instancelist]
will output:
8
16384
This way you do not need any global variables or placeholders that are stored outside of the class definition.
Not usually. You could make your class be capable of that, however:
GLOBAL_MYCLASS_LIST = []
class MyClass(object):
def __init__(self, x, y):
GLOBAL_MYCLASS_LIST.append(self)
self.x = x
self.y = y
def power(self):
print(self.x**self.y)
def divide(self):
print(self.x/self.y)
a = MyClass(2, 3)
b = MyClass(4, 7)
all_powers = [i.power() for i in GLOBAL_MYCLASS_LIST]
Of course, you could also do that without baking it into the class, which is probably cleaner for most cases where you might have different sets of MyClasses:
myclass_list = []
class MyClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
def power(self):
print(self.x**self.y)
def divide(self):
print(self.x/self.y)
myclass_list.append(MyClass(2, 3))
myclass_list.append(MyClass(4, 7))
all_powers = [i.power() for i in myclass_list]
From your question, I believe you would want a bit of dynamism too. Something like below could help:
I have added a function called printBoth() for demonstration.
Note: Python 2.x code below
class MyClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
def power(self):
print "power",self.x**self.y
def divide(self):
print "divide", self.x/self.y
def printBoth(self):
print "x: ", self.x
print "y: ", self.y
class Test:
def __init__(self, items):
self.items = items
def __getattr__(self, key):
def fn():
return [getattr(x,key)() for x in self.items]
return fn
foo = MyClass(2, 3)
bar = MyClass(4, 7)
t = Test([foo,bar])
t.power()
t.divide()
t.printBoth()
Output:
power 8
power 16384
divide 0
divide 0
x: 2
y: 3
x: 4
y: 7
Note: The code can break on many occasions, you neeed to perform additional checks in real implementation.
The important part is here:
def __getattr__(self, key):
def fn():
return [getattr(x,key)() for x in self.items]
return fn
The above function is invoked upon any function call on the Test instance. What is returned is function that takes no arguments. The function runs over all the instances, and invokes the same function on every item on self.items (which is the list of all the instances you want to invoke your function on). The results are returned as a list.
Sure. Put the instances in a list as you create them, then iterate over the list and call the method on each instance. Also, you should change your methods to return rather than print their results, as this is much more flexible. That way you can store the results in a list, write them to a file, do further calculations with them, or print them.
instances = [MyClass(2, 3), MyClass(4, 7)]
results = [x.power() for x in instances]
Just use a loop:
foo = MyClass(2, 3)
bar = MyClass(4, 7)
for i in [foo, bar]:
i.power()
If you are not sure that all instances will have the method, use a hasattr check:
for i in list_of_instances:
if hasattr(i, 'power'):
i.power()
I think all answers are valid, depending on the use case. I would argue that if this class is used in seperated parts of your app/program you wouldn't want to depend on the GLOBAL_MYCLASS_LIST declared some where before (as #amber suggested). You would want to be sure this variable exists and declare it as a Class Variable and have the compute_all as a Class method or even as a static method with #staticmethod decorator (which I think is less relevant to the specific use case.
Again, I would stress that this is a very specific use case, and not very common. so you should think about your design before doing that and not using the more straight pythonic ways offered in other answers.
I would also like to refer you to this nice video of a Pycon lecture about classes in python which does a nice job of explaining this (The decks are here.)

Categories