65

I have a file that is meant to be a utility file. The file should contain a lot of static methods.

Should I define the methods inside a class this way:

#utility.py
class utility(object):
    @staticmethod
    def method1(a,b,c):
        pass

    @staticmethod
    def method2(a,b,c):
        pass

or use it like this (without a class):

#utility.py
def method1(a,b,c):
    pass

def method2(a,b,c):
    pass
Weiner Nir
  • 1,435
  • 1
  • 15
  • 19

3 Answers3

46

The second option is the modus operandi in Python. I mean, if all you're doing is importing functions, then you can do something like this:

from utility import some_func

which will import your function.

Best practice is if you're using only static functions, then just put them in the global namespace of a separate module, it will make your life a lot easier. What you're trying to do is make objects and just fill them in with static methods. Why do this, when you can just define the functions in a .py file?

In fact, what you're trying to do has been done. You're trying to store away some good utility functions. Well, python-requests, is a third party library that is just adored by the majority of Pythonistas just does this. It stores away its good utility functions in a separate module. Here is the example.

Zara
  • 146
  • 1
  • 13
Games Brainiac
  • 80,178
  • 33
  • 141
  • 199
  • It feels more comfort for me to use it the utility.method1(...) way. Should I force myself doing it this way? I really want to use the best practice. – Weiner Nir Oct 27 '13 at 16:42
  • 2
    **NEVER** use `from foo import *` in production code. It makes it impossible to track where imports came from, and can overshadow builtin names. – Lukas Graf Oct 27 '13 at 16:43
  • 2
    Best practice is, if you're using only static functions, then just put them in the global namespace of a separate module, it will make your life a lot easier. – Games Brainiac Oct 27 '13 at 16:43
  • open every second if not every package's `__init__.py` and you'll find `from foo import *` – alko Oct 27 '13 at 16:49
  • @alko That's different: That's the package deliberately using `import *` to define `__all__`, exactly to prevent people using `from package import *` (which they shouldn't) from importing unwanted things. Also: Just because you still see it way too often (NumPy, I'm looking at you) doesn't mean it's a good idea. – Lukas Graf Oct 27 '13 at 16:54
  • Guys I added python-requests as an example :) where this has been done XD – Games Brainiac Oct 27 '13 at 16:57
31

Classes encapsulate both data, and behavior, so as general rules:

  • If you have something only with data, and no methods, it should probably be a namedtuple, not a class, unless you need to modify that data after creating it.
  • If a function accesses instance data, it should be a method.
  • If a function accesses no instance data, but does access class data, it should be a @classmethod.
  • If a function accesses neither instance data nor class data, it should be a standalone function, unless there's some really compelling reason to make it a @staticmethod.
  • If a class only has one method, or one method in addition to __init__(), then you almost certainly can and should rewrite it as a function.

Classes are really easy to abuse, but the temptation to shove everything into a class should really be avoided. You should use them when they make sense, and avoid using them when they don't.

Crowman
  • 25,242
  • 5
  • 48
  • 56
  • Nice sumary. I never found a good use to static methods – Guzman Ojero May 22 '21 at 13:50
  • 1
    To add: "If you have something only with data, and no methods, it should probably be a namedtuple, not a class".You now can also use Data classes a) https://docs.python.org/3/library/dataclasses.html b) https://realpython.com/python-data-classes/ – Guzman Ojero May 22 '21 at 13:53
13

While this question is a little opinion based, I'd say the second one is better. It reduces redundancy. Using the first method, you will have to do:

import utility
utility.utility.method1(...)

or:

from utility import utility
utility.method1(...)

Using the second one however allows you to simply do:

import utility
utility.method1(...)

or:

from utility import method1
method1(...)

If you are making a class that only contains static methods, my question is "why do you need the class?" It contributes nothing positive here.

  • Old thread, but what if you were able to logically group a lot of the utility functions together? You could make several utility modules (e.g. `my_time_utils.py`, `my_string_utils.py`, etc.) which would be great for a few big collections. What about many small collections, though? Then wouldn't it make sense to put logical separators in your `my_string_utils.py` module in the form of classes (e.g. `Punctuation`, `Translation`, `SpellCheck`, etc.)? Therefore, you'd have `from my_string_utils import Punctuation` ... `Punctuation.fix_commas(text)` So, just use classes in one util module? – s g Jan 23 '19 at 03:18