43

I come from a Java background and I'm new to python. I have a couple scripts that share some helper functions unique to the application related to reading and writing files. Some functions associated with reading, some with writing. While searching for the correct approach, I saw this: Static methods in Python?

He mentions in his answer:

Finally, use staticmethod sparingly! There are very few situations where static-methods are necessary in Python, and I've seen them used many times where a separate "top-level" function would have been clearer.

I don't understand top-level functions very well and I'm not sure given this simple example which is better: 1) create a class for a reader with static reader functions and the same for a writer or 2) to declare these helpers as global functions and why?

EDIT: REALLY good article about this subject i just found http://tomayko.com/writings/the-static-method-thing

Community
  • 1
  • 1
Brad
  • 6,106
  • 4
  • 31
  • 43
  • 2
    The thing to remember is that top-level functions in python are still scoped within a module (unless you `from libfoo import *`). It prevents the namespace collision that you have with C, but without having to go to full-blown class-static methods. – Jonathon Reinhart Aug 15 '13 at 22:02
  • 2
    Also related: http://stackoverflow.com/questions/12735392/python-class-static-methods – lmjohns3 Aug 15 '13 at 22:04
  • I wouldn't say the question is the same as mine though, it just illustrates writing free functions in a module. @matteo-italia's answer is the one i was looking for – Brad Aug 15 '13 at 22:12

5 Answers5

55

In Java there's the (IMHO wrong) idea to use classes everywhere, even just group together static functions that don't share any state (and thus such classes will never be instantiated).

Python here begs to differ; if you have functions that don't have some shared state1 (and thus in Java would typically be static functions) and aren't tightly related to a "real" class (=one that is actually instantiated) you just use free functions inside a module.

The reasoning behind this is that a class is needed only when you actually want to instantiate it, thus having a class just as a container for several functions that don't need to share an instance-specific state is useless.

Actually, you can somewhat think of a module as a static class - i.e. a container of functions (=static methods), module variables (=static fields) and types.

The nice thing in Python is that having top-level function doesn't give global namespace pollution problems, since in Python top-level functions/objects/... are still module-scoped. Thus, you can still group functions by module, without the unnecessary class-tax.


  1. actually, they can have some shared state, in form of module-level variables (so, singletons); again, the analogy modules-static classes seems to hold.
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • 2
    @Brad: uhm, what should I illustrate? You just don't write a class and put the free function definitions (`def foo(): ...`) inside the file... – Matteo Italia Aug 15 '13 at 22:06
  • While not required, it's not a bad idea to group functions that don't directly impact control flow in a helpers class as methods decorated with `@staticmethod`. – Evan Plaice Dec 11 '15 at 10:44
14

From the Zen of Python (import this) :

Namespaces are one honking great idea -- let's do more of those!

One of the main reasons to create static methods in a language like Java is to ensure that those methods don't wind up polluting the global namespace. (Although Java enforces its own namespace conventions by disallowing "package-level" functions entirely !) In Python, all "top-level" functions are automatically placed within the namespace of the module containing those functions, so there's no danger of polluting the global namespace this way.

In other words, like many other languages, Python can create namespaces in a few different ways. In this case, there's little need to create a class containing only static methods, when a module serves the same namespacing purpose without the clutter (or cognitive load) associated with defining a class.

dumbledad
  • 16,305
  • 23
  • 120
  • 273
lmjohns3
  • 7,422
  • 5
  • 36
  • 56
  • C++ is a bad example, because it has a namespacing mechanism that's independent from classes (quite similar to Python in this respect, though very different in others). –  Aug 15 '13 at 22:14
  • @delnan Hm, yeah, I know what you mean -- you could replace C++ classes that only contain static methods with a namespace as well, and for the same reasons as in Python. But C++ namespaces aren't automatically restricted to a single file like the Python module namespace system is (or like Java's directory namespace for that matter). – lmjohns3 Aug 15 '13 at 22:20
8

Its a question of namespace pollution. If you have a module with multiple classes and some functions that only make sense for a certain class and its descendents, then make that a static method. The static method can be called either by using the class name or by using an object of the class.

>>> class A(object):
...     @staticmethod
...     def static_1():
...             print 'i am static'
...     def a(self):
...             self.static_1()
...
>>> A.static_1()
i am static
>>> a=A()
>>> a.a()
i am static
>>> a.static_1()
i am static
>>> class B(A):
...     pass
...
>>> b=B()
>>> b.static_1()
i am static
>>>
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • +1 for mentioning inheritance ('descendants'). Presumably, if someone else subclasses this, any static methods would be inherited and any top-level would not. – Jon Coombs Jan 30 '14 at 20:39
  • @JCoombs - right. The static methods won't be seen by classes further up the inheritance chain so you are declaring functionality for this class and its children. Documentation is natural because doc strings for them method will only show for A and its children. – tdelaney Jan 30 '14 at 20:49
7

If the function is related to a class, then make it a static method. For example:

class DBobject():
    name = StringProperty()

    @staticmethod
    def get_by_name(name):
        return db.select('select * from DBobject where name = "%s"' % name)

python = DBobject.get_by_name('python')

That is, the method is completely related to the DBobject class so it should be a static method.

Brent Washburne
  • 12,904
  • 4
  • 60
  • 82
2

One other aspect of Python static methods is that when called on instances, they are polymorphic on the type of the variable they are called on, despite not having an instance of self.

For example:

class BaseClass:
    @staticmethod
    def my_method():
        return 0


class SubclassLeft:
    @staticmethod
    def my_method():
        return "left"


class SubclassRight:
    @staticmethod
    def my_method():
        return "right"


instances = [BaseClass(), SubclassLeft(), SubclassRight()]

for i in instances:
    print(i.my_method())

Running this results in

$ python example.py
0
left
right
andyg0808
  • 1,367
  • 8
  • 18