'Purposely trying to break Python class inheritance, don't understand why it breaks this way
I'm exploring the limits of Python class inheritance, so I wrote a small test to see how much I can get away with - redeclaring properties and overriding functions.
class A:
val : int = 3
def foo(x: int):
print(x)
class B(A):
val : str = 'python'
def foo(x: str):
print(x)
a = A()
b = B()
a.foo(5)
b.foo('test')
print(a.val)
print(b.val)
The resulting output is surprising. I would have expected some kind of exception for redeclaring the property, but instead I get:
Traceback (most recent call last):
File "c:\Development\Playground\hello.py", line 12, in <module>
a.foo(5)
TypeError: A.foo() takes 1 positional argument but 2 were given
I don't see how it interpreting that I am providing two positional arguments for a.foo(5). Granted I am trying to break it but I still want to understand.
Solution 1:[1]
You need a self parameter for instance methods.
class A:
val : int = 3
def foo(self, x: int):
print(x)
class B(A):
val : str = 'python'
def foo(self, x: str):
print(x)
a = A()
b = B()
a.foo(5)
b.foo('test')
print(a.val)
print(b.val)
Output:
5
test
3
python
Solution 2:[2]
Now that I know you are not looking for a fix, but an idea about what the interpreter is doing I can walk you through one line of your code:
a.foo(5)
This line is just a nice way for us programmers to express the idea of calling a method (foo) on an instance (a). This is syntactic sugar and I like to think of the interpreter transforming that text to this text:
A.foo(a, 5)
and then compiling that. Now you can see, when you compare that line of code to the method that you defined: def foo(x: int): that the interpreter is going to say that the method takes one positional argument (x) but you are giving it two: (a, 5)
Solution 3:[3]
I think the error is produced because self was automatically passed since it's a function of a class so your functions have to take self as their first argument
class A:
val : int = 3
def foo(self, x: int):
print(x)
class B(A):
val : str = 'python'
def foo(self, x: str):
print(x)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Fed_Dragon |
| Solution 2 | quamrana |
| Solution 3 |
