python class design (staticmethod vs method)
Asked Answered
R

3

7

What's the nicer way for methods that don't need any passed information (object instance or class) because for example they just do a simple conversion. @staticmethod or method ?

class Foo(object):
    def __init__(self, trees):
        self.money = Foo.trees2money(trees)

    @staticmethod
    def trees2money(trees):
        return trees * 1.337

class Quu(object):
    def __init__(self, trees):
        self.money = self.trees2money(trees)

    def trees2money(self, trees):
        return trees * 1.337
Roundly answered 6/3, 2011 at 17:21 Comment(4)
static methods are useless in python,you could do the same with a normal function...Estradiol
@Srinivas Reddy Thatiparthy: Not really, you add the method to a specific namespace. Though I don't think it (the static method) should be used much.Staghound
@extranon: Well, basically useless. The namespacing may be useful sometimes, but when you're coming from another language you should ignore @staticmethod because whatever you want to do via a static method should propably be done via a free function or class method.Reinaldo
This particular example seems like it is best placed in a module-level function rather that placing it within a class, as Rosh Oxymoron states in his answer.Sheepish
B
8

The choice of the type of method depends on other factors.

You have two cases. The first case is when the method has to be part of the class interface - e.g. it has to be called by users, or it has to be overridable in subclasses, or it uses the information in self, or it's likely that in a future version of the software you might need any of those.

In this first case you'd often either use a normal method (this is when the method relates to the instances and not to the class) or a classmethod (when the method relates to the class, e.g. it's an alternative constructor, a method for discovering class features, etc.). In both cases you can use a staticmethod instead if no information from the class/instance is used by the method, but you don't gain anything from doing so. And it would also break your ability to do cls.method(instance, *args) which is already too much for gaining nothing.

The second case is when the method isn't a part of the class in any way. Then it is generally advisable to use a function - the method is not really part of the interface, so it has no place there. Your example seems to be that case unless you want to override the tree/money calculator in subclasses, but that largely depends on what you're doing with it.

A special case is private methods - then you might want to use a method even if it's not really related to the class, private methods aren't part of the interface so it doesn't matter where you put them. Using a staticmethod still doesn't gain you much but there isn't any reason not to use it either.

There's actually one case where staticmethod is very helpful - when you're putting external functions (or other objects) in the class.

class Foo(object):
     trees2money = staticmethod(calculators.trees2money)
     foo = staticmethod(calculators.bar)

But when you have a static definition of the class, that's not really great, because you can always do the following instead.

class Foo(object):
     def trees2money(self, trees):
         """Calculator for trees2money, you can override when subclassing"""
         return calculators.trees2money(trees)
     @property
     def foo(self):
         """The foo of the object"""
         return calculators.bar

Which gives you a better idea what these objects do when reading the source and even allows you to add documentation. But it might still come in handy when you're building classes dynamically, or you're adding them in a metaclass (creating a wrapper method manually isn't very convenient).

Besant answered 6/3, 2011 at 17:41 Comment(1)
+1: well said. I also find that the only time I use static methods are as private utility functions used within the class. And even that is very rare.Sheepish
D
2

My general rule, for all Object Oriented design, is that if a class has no state, consider using static methods. If the class has state, use instance methods - hands down.

Furthermore, if the class indeed has no state, reflect for a few minutes and see if you cannot move the static behavior closer to the data and thereby eliminate those static methods with an Extract Method refactoring.

Dwinnell answered 6/3, 2011 at 17:24 Comment(7)
@Mike: If the method makes no use of the state, isn't the presence or absence of state irrelevant? Don't know too much OOPS theory, am I missing something?C
The method represents the behavior of the class, whereas the state represents the data. We're shooting for a nice symmetry, where classes have both. If the method isn't making use of the class state, then the class might not be very cohesive.Dwinnell
If a class has no state, I might consider making its methods into free functions. My thought being that if there's no state to read/modify, why even have the class at all? (This obviously doesn't apply to languages like Java where every function has to be part of a class.)Sheepish
@Sheepish If I ever think to use a global function in an OO language, I become highly suspicious that there's a better place (class) to put the function.Dwinnell
We'll just have to agree to disagree.Sheepish
There aren't really any global functions in Python, though. Functions you write are only "global" to a module. That's not very global at all, really.Babylonia
I find unbounded functions global - but that's my understanding.Dwinnell
C
0

Any methods that do not use names from the object namespace should by classmethods, and those that do not use names from the class namespace either - staticmetdods, or even be put on the module level as functions.

When the actual object method is used, the expected behavior is that some other attrubutes/methods from the same object will be accessed.

Chieftain answered 6/3, 2011 at 17:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.