I have a class that includes some auxiliary functions that do not operate on object data. Ordinarily I would leave these methods private, but I am in Python so there is no such thing. In testing, I am finding it slightly goofy to have to instantiate an instance of my class in order to be able to call these methods. Is there a solid theoretical reason to choose to keep these methods non-static or to make them static?
-
If they don't affect an object then why should they be methods at all? – Ignacio Vazquez-Abrams Oct 09 '17 at 15:02
-
Normally, I would not make them part of the class at all. – juanpa.arrivillaga Oct 09 '17 at 15:03
-
They check inputs and do some useful things related to this class. It makes sense to keep them with it rather than to put them in something totally different. – Pavel Komarov Oct 09 '17 at 15:04
-
1"Ordinarily I would leave these methods private, but I am in Python so there is no such thing" => well yes there is. Just prefix your function/method/attribute/whatever with a single leading underscore and everyone will know it's not part of the API. – bruno desthuilliers Oct 09 '17 at 15:17
-
That's just a convention; it doesn't actually make anything private. – Pavel Komarov Oct 09 '17 at 15:43
2 Answers
If a method does not need access to the current instance, you may want to make it either a classmethod, a staticmethod or a plain function.
A classmethod will get the current class as first param. This enable it to access the class attributes including other classmethods or staticmethods. This is the right choice if your method needs to call other classmethods or staticmethods.
A staticmethod only gets it's explicit argument - actually it nothing but a function that can be resolved on the class or instance. The main points of staticmethods are specialization - you can override a staticmethod in a child class and have a method (classmethod or instancemethod) of the base class call the overridden version of the staticmethod - and eventually ease of use - you don't need to import the function apart from the class (at this point it's bordering on lazyness but I've had a couple cases with dynamic imports etc where it happened to be handy).
A plain function is, well, just a plain function - no class-based dispatch, no inheritance, no fancy stuff. But if it's only a helper function used internally by a couple classes in the same module and not part of the classes nor module API, it's possibly just what you're looking for.
As a last note: you can have "some kind of" privacy in Python. Mostly, prefixing a name (whether an attribute / method / class or plain function) with a single leading underscore means "this is an implementation detail, it's NOT part of the API, you're not even supposed to know it exists, it might change or disappear without notice, so if you use it and your code breaks then it's your problem".

- 75,974
- 6
- 88
- 118
-
Props on highlighting inheritance. It's a good reason to keep a static method inside a class. – Valentin B. Oct 09 '17 at 15:19
-
Also on your last point, a single leading underscore is a kind disclaimer saying "I hope you know what you're doing because touching this might break the code". A **double** leading underscore actually hides it a bit more (say you define `__foo` in class `Bar`, you will only be able to access it at `instance_of_Bar._Bar__foo`, it's the ultimate "do NOT touch this!" python warning). – Valentin B. Oct 09 '17 at 15:23
-
1@ValentinB. I didn't mention the double underscore / name mangling part for a reason: it's really of very little use in pythonic code - actually the only good reason (I've ever found) to use it is to prevent some implementation-critical part of a base class to be accidentaly overriden by a child class. Practically I might have used it a couple time in the past 18 years, and very seldom seen it in other peoples source code. Yet most newcomers (specially coming from C++/Java) jump on it thinking that they have to make everything "private" then wonder why their code doesn't work as expected... – bruno desthuilliers Oct 09 '17 at 15:35
-
I have a far more modest experience, but personally never used it. I totally agree with you and just mentionned it for completeness's sake, hiding and forbidding things is not really a pythonic thing to do usually. – Valentin B. Oct 09 '17 at 15:41
If you want to keep said methods in the class just for structural reasons, you might as well make them static, by using the @staticmethod
decorator:
class Foo():
@staticmethod
def my_static_method(*args, **kwargs):
....
Your first argument will not be interpretted as the object itself, and you can use it from either the class or an object from that class. If you still need to access class attributes in your method though, you can make it a class method:
class Bar():
counter = 0
@classmethod
def my_class_method(cls, *args, **kwargs):
cls.counter += 1
...
Your first argument of the class method will obviously be the class instead of the instance.
If you do not use any class or instance attribute, I can see no "theoretical" reason to not make them static. Some IDE's even highlight this as a soft warning to prompt you to make the method static if it does not use or mutate any class/instance attribute.

- 602
- 6
- 18
-
"Your first argument will not be interpretted as the object itself" => "the current instance will not be injected as the first argument" - it's not a matter of "interpretation" but of what really gets passed to the function. – bruno desthuilliers Oct 09 '17 at 15:38
-
I meant it as in "what the interpretter sees", but I guess that you are rigourously right ! – Valentin B. Oct 09 '17 at 15:42