Reputation: 60751
Let's say I want to override a function like __int__
in a Python class so that I may do something like this.
class A(object):
def __init__(self):
self.__int__ = lambda: 1
a = A()
print int(a)
I expect that it would output "1" here instead of produce this error message
TypeError: int() argument must be a string or a number, not 'A'
When __int__
instead becomes a method built into the class it works as expected. Why? (This problem exists with any of the double underscore functions also)
Upvotes: 4
Views: 257
Reputation: 172229
If we for the moment ignore that you are asking about special methods, then your code would look like this:
class A(object):
def __init__(self):
self.a_fun = lambda: 1
Is written more clearly like this:
class A(object):
def __init__(self):
self._int = 1
def a_fun(self):
return self._int
The resulting code isn't exactly the same, but close enough for it to not make much of a difference. The only difference is that the _int
name has to be looked up as an attribute.
But if we now change it back to be a special method, it looks like this:
class A(object):
def __init__(self):
self.__int__ = lambda: 1
vs:
class A(object):
def __init__(self):
self._int = 1
def __int__(self):
return self._int
And now there is a very big difference: The second variant works, the first one doesn't. This is because special methods is always looked up on the class, not the instance. This is by design.
So instead of trying to be clever, just write what is clear and readable. In Python that tends to work best. ;-)
Upvotes: 1
Reputation: 37319
That appears to be one more bit of magic in the __
magic methods. Unlike other methods, they're not looked up on the class instances when called implicitly.
It's well documented that they don't get resolved with the __getattribute__
magic method (and it would be a nice paradox if they did, since __getattribute__
would have to call itself to resolve its own name). But not checking the instances surprises me.
It's discussed a bit here, under the header "Special Method Lookup": http://segfaulthunter.github.io/articles/biggestsurprise/
For instances of new-style classes, all special method lookup that is done implicitely is done in the class struct. Thus changing an instance's
__str__
attribute does not effect the result of str(). Still, explicitely getting the attribute from the instance gives you the method in the instance.
I will be curious to see if anyone else can offer a more detailed explanation.
Upvotes: 3