Magic __init__ and regular init methods in a python class
https://softwareengineering.stackexchange.com/questions/369844
-
05-02-2021 - |
Question
Is naming a regular method init
only confusing or is it an error?
class A:
def __init__(self, x):
self.x = x
def init(self, y):
self.y = y**2
def reset(self):
self.y = 0
I have encountered such a construction during review. Should I mark is as an issue?
La solution
I'd suggest using setup
instead of init
to remove any ambiguity for the reader. While syntactically correct, unreadable/ambiguous code results in harder-to-maintain products.
Also, if such methods exist in a class (init
, reset
, setup
...), I always try to use them in the constructor itself as they're usually meant to leave the object in a known state. For instance:
def __init__(self, x):
self.reset()
self.x = x
This helps reduce the code duplication and simplify the possible states an object can be in.
Autres conseils
Should I mark is as an issue?
That really depends on the coding standard you are using.
Is it confusing? Yes, to the human. Especially in verbal conversations, having to clarify whether you mean __init__
vs init
will waste people's time.
If you want to argue against this practice, use your coding standards' naming guidelines. Many coding standard species that names should be clear and unambiguous, and names like this are ambiguous to the human.
Is it an error? No. The python parser and interpreter won't error out, as it is unambiguous to it. To the python compiler/interpreter, those are unambiguous and there's a totally clear difference between __init__
and init
.
One problem with this class is that reset
doesn't result in an A
that "has just been constructed", which will probably surprise people.
If it were either
class A:
def __init__(self, x):
self.x = x
def init(self, y):
self.y = y**2
def reset(self):
del(self.y)
or (more preferably)
class A:
def __init__(self, x):
self.x = x
self.y = 0
def init(self, y):
self.y = y**2
def reset(self):
self.y = 0
then it would be less bad.
That being said, I dislike any class that has a setup
, gather members
, init
or whatever named method, which users must call before the real purpose of the class can be used. If you really need two phase initialisation, return a factory object from the first call, and only instantiate on the second
class A:
def __init__(self, x, y):
self.x = x
self.y = y**2
# members can assume y exists
def defferedA(x):
def inner(y):
return A(x, y)
return inner
That makes no sense.
What is something called init
supposed to do besides initializing an object with an initial state, which is, what a constructor does, which in turn is, what __init__
should do in this case?
In the context given, init_y
whould make (more) sense.
Perhaps classmethods help you in this context - but hence your example is contrieved, I do not know.