Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using static methods in python - best practice

When and how are static methods suppose to be used in python? We have already established using a class method as factory method to create an instance of an object should be avoided when possible. In other words, it is not best practice to use class methods as an alternate constructor (See Factory method for python object - best practice).

Lets say I have a class used to represent some entity data in a database. Imagine the data is a dict object containing field names and field values and one of the fields is an ID number that makes the data unique.

class Entity(object):
    def __init__(self, data, db_connection):
        self._data = data
        self._db_connection

Here my __init__ method takes the entity data dict object. Lets say I only have an ID number and I want to create an Entity instance. First I will need to find the rest of the data, then create an instance of my Entity object. From my previous question, we established that using a class method as a factory method should probably be avoided when possible.

class Entity(object):

    @classmethod
    def from_id(cls, id_number, db_connection):
        filters = [['id', 'is', id_number]]
        data = db_connection.find(filters)
        return cls(data, db_connection)

    def __init__(self, data, db_connection):
        self._data = data
        self._db_connection


# Create entity
entity = Entity.from_id(id_number, db_connection)

Above is an example of what not to do or at least what not to do if there is an alternative. Now I am wondering if editing my class method so that it is more of a utility method and less of a factory method is a valid solution. In other words, does the following example comply with the best practice for using static methods.

class Entity(object):

    @staticmethod
    def data_from_id(id_number, db_connection):
        filters = [['id', 'is', id_number]]
        data = db_connection.find(filters)
        return data


# Create entity
data = Entity.data_from_id(id_number, db_connection)
entity = Entity(data)

Or does it make more sense to use a standalone function to find the entity data from an ID number.

def find_data_from_id(id_number, db_connection):
    filters = [['id', 'is', id_number]]
    data = db_connection.find(filters)
    return data


# Create entity.
data = find_data_from_id(id_number, db_connection)
entity = Entity(data, db_connection)

Note: I do not want to change my __init__ method. Previously people have suggested making my __init__ method to look something like this __init__(self, data=None, id_number=None) but there could be 101 different ways to find the entity data so I would prefer to keep that logic separate to some extent. Make sense?

like image 661
Yani Avatar asked Feb 22 '13 05:02

Yani


People also ask

Should you use static methods in Python?

Static methods have a limited use case because, like class methods or any other methods within a class, they cannot access the properties of the class itself. However, when you need a utility function that doesn't access any properties of a class but makes sense that it belongs to the class, we use static functions.

Is it good practice to make methods static?

Static Methods/Variables are bad practice. In short: Yes. There are many disadvantages and static methods should almost never be used. Static methods allow procedural/functional code to be shoe-horned into an Object Oriented world.

Is static method faster Python?

It looks like staticmethod is slightly faster (likely just because it doesn't need to pass an argument into the function at all), but we're talking about a difference of 3 milliseconds for 100,000 calls, which is nanoseconds per call in cost.

When should you use a static method when your method?

You should consider making a method static in Java : 1) If a method doesn't modify the state of the object, or not using any instance variables. 2) You want to call the method without creating an instance of that class.


1 Answers

When and how are static methods suppose to be used in python?

The glib answer is: Not very often.

The even glibber but not quite as useless answer is: When they make your code more readable.


First, let's take a detour to the docs:

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

So, when you need a static method in C++, you need a static method in Python, right?

Well, no.

In Java, there are no functions, just methods, so you end up creating pseudo-classes that are just bundles of static methods. The way to do the same thing in Python is to just use free functions.

That's pretty obvious. However, it's good Java style to look as hard as possible for an appropriate class to wedge a function into, so you can avoid writing those pseudo-classes, while doing the same thing is bad Python style—again, use free functions—and this is much less obvious.

C++ doesn't have the same limitation as Java, but many C++ styles are pretty similar anyway. (On the other hand, if you're a "Modern C++" programmer who's internalized the "free functions are part of a class's interface" idiom, your instincts for "where are static methods useful" are probably pretty decent for Python.)


But if you're coming at this from first principles, rather than from another language, there's a simpler way to look at things:

A @staticmethod is basically just a global function. If you have a function foo_module.bar() that would be more readable for some reason if it were spelled as foo_module.BazClass.bar(), make it a @staticmethod. If not, don't. That's really all there is to it. The only problem is building up your instincts for what's more readable to an idiomatic Python programmer.

And of course use a @classmethod when you need access to the class, but not the instance—alternate constructors are the paradigm case for that, as the docs imply. Although you often can simulate a @classmethod with a @staticmethod just by explicitly referencing the class (especially when you don't have much subclassing), you shouldn't.


Finally, getting to your specific question:

If the only reason clients ever need to look up data by ID is to construct an Entity, that sounds like an implementation detail you shouldn't be exposing, and it also makes client code more complex. Just use a constructor. If you don't want to modify your __init__ (and you're right that there are good reasons you might not want to), use a @classmethod as an alternate constructor: Entity.from_id(id_number, db_connection).

On the other hand, if that lookup is something that's inherently useful to clients in other cases that have nothing to do with Entity construction, it seems like this has nothing to do with the Entity class (or at least no more than anything else in the same module). So, just make it a free function.

like image 82
abarnert Avatar answered Sep 30 '22 10:09

abarnert