Reputation: 61
I'm writing a set of custom classes with inheritance using Python. Here is the code, simplified:
class Parent(object):
__slots__ = ['a','b']
def __init__(self, a:int, b:int):
self.a = a
self.b = b
def myfunc(self,s)->int:
return self.a + s.a
class Child(Parent):
__slots__ = ['c']
def __init__(self, a:int, b:int, c:int):
super().__init__(a,b)
self.c = c
def myfunc(self,s)->int:
return self.a + s.a + s.c
def main():
dad = Parent(1,2)
son = Child(4,8,16)
print(dad.myfunc(son))
print(son.myfunc(son))
print(son.myfunc(dad))
if __name__ == "__main__":
main()
Upon running the function, I get this output (which I understand):
5
24
Error: Parent has no attribute 'c'
The myfunc() definition in Child requires that both self AND s are instances of Child.
My ideal functionality for this code is that I want to implement method overloading. When son.myfunc(dad)
is called, I want it to check the type of dad. If dad is also a Child
, it should use Child
's definition of myfunc()
. Otherwise, if dad isn't a Child
, son should fall back to using the definition of myfunc()
in Parent
. So, for the above code, I'd want:
5
24
5
I would've thought that I could implement this functionality as follows, specifying the parameter types of myfunc()
:
class Parent(object):
__slots__ = ['a','b']
def __init__(self, a:int, b:int):
self.a = a
self.b = b
def myfunc(self, s:Parent)->int:
return self.a + s.a
class Child(Parent):
__slots__ = ['c']
def __init__(self, a:int, b:int, c:int):
super().__init__(a,b)
self.c = c
def myfunc(self,s:Child)->int:
return self.a + s.a + s.c
def main():
dad = Parent(1,2)
son = Child(4,8,16)
print(dad.myfunc(son))
print(son.myfunc(son))
print(son.myfunc(dad))
if __name__ == "__main__":
main()
However, this doesn't work. Python and my IDE tell me that "Parent is not defined"
by the time I use it to specify the input type of Parent's myfunc()
, and the same for Child
. I think I get what it's saying ('Parent
' won't mean anything until the compiler finishes reading Parent, so it can't be specified as the parameter type), but I don't know how to work around this.
How can I implement my intended functionality? Is there some keyword like 'this'
or 'self'
that can be used to refer to the current class's type for these specifications? Even if method overloading doesn't work in this way- is there a way for a single class (Parent
) to specify itself as the parameter type of one of its functions?
Edit: I'm aware that Python parameter types are annotations for readability and error-checking, and they don't actually cause errors/failures if called with a different type. The second code segment was created to help communicate what I want to have occur. I'm aware I might have to add a check like isinstance() at the start of myfunc, but (a) I would like to avoid it if there is an alternative (b) if I did discover in the body of Child's myfunc() that I wanted to call the Parent's instead, I'm not certain of how I'd do that.
Upvotes: 6
Views: 8656
Reputation: 59184
You have two separate issues:
In order to type-hint a method that returns its own class (forward reference) you should use a string:
class Parent(object):
def myfunc(self, s: "Parent") -> int:
Update: Starting with Python 3.11, you can also use the Self
annotation:
from typing import Self
class Parent(object):
def myfunc(self, s: Self) -> int:
You can use isinstance
to check for type, i.e.
def myfunc(self, s: "Child") -> int:
return (self.a + s.a + s.c) if isinstance(s, Child) else (self.a + s.a)
As a side note the type of s
in your Child.myfunc
should probably be Parent
.
Update: Per your comment, the following should be possible:
class Parent(object):
# ...
def _myfunc(self, s: "Parent") -> int:
return self.a + s.a
def myfunc(self, s: "Parent") -> int:
return type(s)._myfunc(self, s)
class Child(Parent):
# ...
def _myfunc(self, s: "Parent") -> int:
return self.a + s.a + s.c
Upvotes: 7