I am working on a large program (more than 10k lines of code).
Below is a (hopefully not over-simplified) example of a problem I sometimes face:
class MyClass1(object):
def func_1(self):
return self.func_2() * 2
class MyClass6(MyClass1):
def func_2(self):
return 10
a = MyClass6().func_1()
print(a) # Prints 20
I need to use in MyClass1
a method that is defined later on in MyClass6
.
Using this code as is, works fine. I get quite a visible warning:
enter image description here
and I can add a comment so that I know what is going on in the future in case I need to debug it. However, I can't use options in my IDE like Find usages, Rename etc.
Alternatively, I can use @abstractmethod
to make it explicit that funct_2
is defined in a child class and my IDE options would work fine:
import abc
class MyClass1(metaclass=abc.ABCMeta):
@abc.abstractmethod
def func_2(self):
return 'zzzz'
def func_1(self):
return self.func_2() * 2
class MyClass5(MyClass1):
def func_2(self):
return 10
a = MyClass5().func_1()
print(a) # Prints 20
... but I think this is not the way to go. For example I get weak warnings from my IDE for classes inbetween MyClass1
and MyClass5
(e.g. "MyClass4 has to implement abstract method...").
Question:
What is the right way to deal with a parent class using a method that is defined in a child class?
Edit:
Some extra details:
MyClass1
is never called on its own. Also func_2()
has to be defined in MyClass6
because everything it needs is defined there as well.
3 Answers 3
If func_2
in MyClass1
doesn't contain any logic and is expected to be declared by child classes (and MyClass1
is never used directly), then making the class abstract like you did is a reasonable approach and makes the code self-documenting and explicit.
If:
func_2
inMyClass1
contains logic (eventually overwritten in child classes),Or
MyClass1
may be used as-is without any inheritance,Or a child should not be forced to implement
func_2
,
then declare func_2
in MyClass1
, containing the default logic (this is similar to virtual methods in other languages such as C#). In your case, it will return the default value. For methods which don't return anything, you may use pass
keyword:
def func_2():
pass
Finally, you may always rely on a dynamic nature of Python and let children deal with the declaration of func_2
, expecting errors during runtime if the method is missing.
-
1
MyClass1
is never called on its own. I guess I ll insert that in my question. As for usingpass
, i avoided it since it shows a yellow warning in some cases infunc_1
.user– user2015年05月16日 21:39:17 +00:00Commented May 16, 2015 at 21:39 -
2@user5061: when do you talk about warnings, do you mean warnings in your IDE? It looks like your editor reports warnings which are just informative rather than indicative of a error in your code.Arseni Mourzenko– Arseni Mourzenko2015年05月16日 21:41:28 +00:00Commented May 16, 2015 at 21:41
-
I'm talking about IDE warnings. They might be simply informative, but it hinders refactoring since they are mixed with other important warnings (and I have to find which is which).user– user2015年05月18日 15:03:06 +00:00Commented May 18, 2015 at 15:03
One option is to make it clear to the IDE and your users that there is a method, but you can't use the base class version:
class MyClass1(object):
def func_2(self):
raise NotImplementedError
def func_1(self):
return self.func_2() * 2
You won't get warnings from intermediate classes that don't define func_2
, but will get an error if you call it on a class that hasn't overridden it. The other option, pass
, can hide these errors in some cases.
-
I did not expect it, but my IDE produces the same warnings for your suggested solution as it does with
ABCMeta
solution: "Class MyClass4 has to implement abstract method...". Using another exception instead ofNotImplementedError
removes those warnings.user– user2015年05月18日 15:15:33 +00:00Commented May 18, 2015 at 15:15
If your problem is only the warnings of IDE, you can avoid it using 2 solutions
solution 1, meta class
class ABCMeta():
def func_2(self):
return 1 #any valid value, just to your IDE dont complain
class MyClass1(ABCMeta):
def func_1(self):
return self.func_2() * 2
class MyClass5(MyClass1):
def func_2(self):
return 10 #the value you really want to use
a = MyClass5().func_1()
print(a) # Prints 20
solution 2, sintetic:
class MyClass1(ABCMeta):
def func_2(self):
return 1 #any valid value, just to your IDE dont complain
def func_1(self):
return self.func_2() * 2
class MyClass5(MyClass1):
def func_2(self):
return 10 #the value you really want to use
-
31. Meta-class has a specific meaning, and that isn't it. 2. What does sintetic mean? Syntactic? Synthetic?jonrsharpe– jonrsharpe2015年05月17日 07:23:17 +00:00Commented May 17, 2015 at 7:23