Module function vs staticmethod vs classmethod vs no decorators: which idiom is more pythonic?

I am a Java developer who played and ran Python. I recently stumbled upon this article that mentions common mistakes that Java programmers make when they pick up Python. The first caught my eye:

The static method in Java does not translate into a class of the Python class. Oh, of course, this leads to more or less the same effect, but the goal of the classmethod is to actually do what is usually not possible even in Java (for example, inheriting a constructor other than the standard one). The idiomatic translation of a static Java method is usually a module level function, not a class or static method. (And static final fields should translate to module level constants.)

This is not a big performance issue, but a Python programmer who needs to work with Java idiom code like this will be pretty annoyed by typing Foo.Foo.someMethod when it should just be Foo.someFunction. But keep in mind that calling a class method involves an additional allocation of memory that calls the static method or method.

Oh, and all of these Foo.Bar.Baz attribute chains are also not provided for free. In Java, these dot names are looked up by the compiler, so at run time it really doesn't matter how many of them you have. In Python, searches are performed at runtime, so each point is counted. (Remember that in Python, “Flat is better than nested,” although it is more associated with “Calculated Odds” and “Simple is better than complex” than with performance.)

I found this a bit strange because the documentation for staticmethod says:

Static methods in Python are similar to those that exist in Java or C ++. Also see Classmethod () for a variant that is useful for creating alternative class constructors.

Even more perplexing is that this code:

class A: def foo(x): print(x) A.foo(5) 

The crash, as expected, in Python 2.7.3, but works fine in 3.2.3 (although you cannot call a method in instance A only for the class.)

So, there are three ways to implement static methods (four, if you think using the class method), each of which has subtle differences, one of which is apparently undocumented. This seems to contradict the Python mantra . There should be one — and preferably only one — an easy way to do this. Which idiom is Pythonic itself? What are the pros and cons of each?

Here is what I understand so far:

Module function:

  • Prevents the problem Foo.Foo.f ()
  • Contaminates the module namespace more than alternatives
  • No inheritance

STATICMETHOD:

  • Saves functions associated with the class inside the class and from the module namespace.
  • Allows you to call a function in instances of the class.
  • Subclasses can override a method.

classmethod:

  • Identical to staticmethod, but also passes the class as the first argument.

Normal method (Python 3 only) :

  • Identical for staticmethod, but cannot call a method for class instances.

Can I say this? It's not a problem? Please, help!

+42
python static-methods
Aug 03 '12 at 1:50
source share
3 answers

The easiest way to think about this is to think in terms of what type of object the method needs to do its job. If your method needs access to the instance, make it the usual method. If he needs access to the class, make it a classmethod. If it does not need access to the class or instance, make it a function. It is rarely necessary to do something with a static method, but if you find that you want a function to be “grouped” with a class (for example, therefore it can be redefined), even if it does not need access to the class, I think you can do it static method.

I would add that the put function at the module level does not "pollute" the namespace. If functions are intended to be used, they do not pollute the namespace; they use it in the same way as its use. Functions are legitimate objects in a module, like classes or something else. There is no reason to hide a function in a class if it has no reason to be there.

+51
Aug 03 2018-12-12T00:
source share

BrenBarn's excellent answer, but I would change "If it doesn’t need access to the class or instance, make it a function":

'If he does not need access to the class or instance ... but there is thematically related to the class (typical example: helper functions and conversion functions used by other methods of the class or used by alternative constructors), then use staticmethod

otherwise make it a module function

+19
Apr 18 '13 at 10:02
source share

This is actually not an answer, but a long comment:

Even more perplexing is that this code:

  class A: def foo(x): print(x) A.foo(5) 

Failure, as expected, in Python 2.7.3, but works fine in 3.2.3 (although you cannot call a method in instance A, only in the class.)

I will try to explain what is happening here.

This, strictly speaking, is an abuse of the usual instance method protocol.

Here you define a method, but with the first (and only) parameter, not named self , but x . Of course, you can call the method on instance A , but you will have to call it like this:

 A().foo() 

or

 a = A() a.foo() 

therefore, an instance is assigned to the function as the first argument.

The ability to call ordinary methods through a class has always been there and works

 a = A() A.foo(a) 

Here, when you call a class method, not an instance, it does not get its first parameter set automatically, but you have to provide it.

As long as this is instance A , everything is fine. Giving him something else is an abuse of the IMO protocol and therefore the difference between Py2 and Py3:

In Py2, A.foo converted to an unrelated method and therefore requires that its first argument be an instance of the class in which it "lives". Calling him with something else will fail.

In Py3, this check has been removed, and A.foo is only the original function object. So you can call it all as the first argument, but I would not do that. The first parameter of the method should always be called self and have the semantics of self .

+14
May 4 '13 at 20:40
source share



All Articles