In the codebase I’m working on, several classes define their __str__
method as def __str__(self, *args, **kwargs)
. As far as I can tell, they don’t seem to actually do anything with the extra arguments, but it got me wondering why this pattern is so pervasive. Was there ever a time that this was useful?
There has never been a time that __str__
has taken arbitrary arguments.
The special “dunder” (Double UNDERscore) method __str__
gets called when you try to convert an object into a string, e.g. using str(obj)
. There are no additional arguments accepted by str
and the interpreter never passes additional arguments to __str__
, so unless their code is directly calling the dunder method (a minor no-no), the extra *args, **kwargs
are pointless.
By J-M0 via Discussions on Python.org at 12May2022 19:14:
In the codebase I’m working on, several classes define their
__str__
method asdef __str__(self, *args, **kwargs)
. As far as I can tell,
they don’t seem to actually do anything with the extra arguments, but
it got me wondering why this pattern is so pervasive. Was there ever a
time that this was useful?
Do they define it in terms of a superclass’s __str__
maybe? If your
overriding a method from a superclass a common pattern is:
def x(self, *a, **kw):
... do something special involving calling super().x(*a,**kw) ...
Which calls the superclass x()
method with whatever arguments were
supplied, then does something specific to the subclass with the result.
But if their __str__
is not using the arguments, I’d take it as a sign
that someone is blindly following a pattern rather than doing something
sensible. Unused arguments are usually a sign of a potential bug, and
various lint programs will warn about that.
Particularly with dunder methods like __str__
, whose parameters are
usually very rigid because they’re called indirectly via things with no
scope for passing arbitrary parameters, I thnk this is almost never
useful. You almost never call a dunder method directly - they’re meant
to express mechanism for other things which don’t look so much like a
function call.
Even if the dunder method is a thin wrapper for a complex function:
def funky_format(self, formating_args_here....)
... return self as a string in many ways ...
def __str__(self):
return self.funky_format(args for use in str here ....)
I’d expose the complex function directly as above, and leave __str__
with no arguments. Maybe its call to funky_format
might match the
defaults for that function and therefore have no arguments:
def __str__(self):
return self.funky_format()
but I would still have __str__
take no arguments, and funky_format
available for the other uses, whatever they might be.
Cheers,
Cameron Simpson cs@cskk.id.au