(picture from Dex Ezekiel)
Today, I was playing with risky naming conflicting (that I generally avoid) and I get confused by a class method/attribute resolution in python.
Specifically I was playing with classes and code samples like the following:
# arg arg arg
class arg():
def arg(self, arg=None):
self.arg = arg
print("arg")
arg = arg()
arg.arg()
And I was confused by the scope of self
:
class parent():
def __init__(self):
self.f() # Boom
def f(self):
return
class child(parent):
def __init__(self):
self.f = "not a method"
super().__init__()
child() # Boom (see above)
I intended that self.f()
in parent class would call the parent function but it first resolved to child attribute and produced and error:
Traceback (most recent call last):
File "module.py", line 17, in <module>
child()
File "module.py", line 14, in __init__
super().__init__("tib")
File "module.py", line 6, in __init__
self.f()
TypeError: 'str' object is not callable
It's not that strange when you think about it (to get the most "specialized" or "downward" method/attribute) but how do you restrict to the parent class scope with just no method resolution?
Do you know dear fellow python developers?
I don't need it, but I'm curious 😃
If yes, please comment! 😃
Top comments (4)
One thing I noticed while using super is - in pycharm it add parameters automatically but in VS code it doesn't.
Try it like -
super(child, self).__init__()
Though this is 2.x style but I it working in such scenorio.
Better way is to use @abstractmethod or something like - stackoverflow.com/a/57102294/2001559
P.S> I am also new to this world and learning
This
super
variant is not working for me (python3.7)So what's going on here is that the
f
method belongs to theparent
class, and is correctly inherited by thechild
class. Thef
field, however, belongs to an instance of thechild
class, not the class itself, and therefore masks the method. I'm not sure what you're actually trying to achieve, as if you'd like to have a string in your child class that doesn't override the parent, its probably best just to give it another name. You can get the result you're expecting by having an instance field holding the method though:This is a bit confusing when you start out, as it feels like methods annotated with
@classmethod
should beling to the class, and those not annotated should belong to the instance. In practice, however, that would mean a copy of every method would have to reside with every instance, which would be terrible wasteful. In fact, the@classmethod
annotation just means that the method is called with the class a the first parameter not the instance.Also just as an aside, there is a style standard for python called PEP8 and that says that classes should have capital letters, it doesn't make your code work any differently though.
I hope that helps!
Thank you! :)