Static Methods in Python

Static methods in Python?

Yep, using the staticmethod decorator:

class MyClass(object):
@staticmethod
def the_static_method(x):
print(x)

MyClass.the_static_method(2) # outputs 2

Note that some code might use the old method of defining a static method, using staticmethod as a function rather than a decorator. This should only be used if you have to support ancient versions of Python (2.2 and 2.3):

class MyClass(object):
def the_static_method(x):
print(x)
the_static_method = staticmethod(the_static_method)

MyClass.the_static_method(2) # outputs 2

This is entirely identical to the first example (using @staticmethod), just not using the nice decorator syntax.

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.


The following is verbatim from the documentation::

A static method does not receive an implicit first argument. To declare a static method, use this idiom:

class C:
@staticmethod
def f(arg1, arg2, ...): ...

The @staticmethod form is a function decorator – see the description of function definitions in Function definitions for details.

It can be called either on the class (such as C.f()) or on an instance (such as C().f()). The instance is ignored except for its class.

Static methods in Python are similar to those found in Java or C++. For a more advanced concept, see classmethod().

For more information on static methods, consult the documentation on the standard type hierarchy in The standard type hierarchy.

New in version 2.2.

Changed in version 2.4: Function decorator syntax added.

What is static method in python

Have you already read this?

https://en.wikipedia.org/wiki/Method_(computer_programming)

Especially this?

https://en.wikipedia.org/wiki/Method_(computer_programming)#Static_methods

Explanation

In OOP you define classes that you later on instantiate. A class is nothing more than a blueprint: Once you instantiate objects from a class your object will follow exactly the blueprint of your class. That means: If you define a field named "abc" in your class you will later on have a field "abc" in your object. If you define a method "foo()" in your class, you will later on have a method "foo()" to be invoked on your object.

Please note that this "on your object" is essential: You always instantiate a class and then you can invoke the method. This is the "normal" way.

A static method is different. While a normal method always requires to have an instance (where you then can invoke this method at) a static method does not. A static method exists independently from your instances (that's why it is named "static"). So a static method is associated with your class definition itself and therefore is always there and therefore can be invoked only at your class itself. It is completely independent from all instances.

That's a static method.

Python's implementation is a bit ... well ... simple. In details there are deviations from this description above. But that does not make any difference: To be in line with OOP concepts you always should use methods exactly as described above.

Example

Let's give you an example:

class FooBar:

def someMethod(self):
print("abc")

This is a regular (instance) method. You use it like this:

myObj = FooBar()
myObj.someMethod()

If you have ...

myObjB = FooBar()
myObjB.someMethod()

... you have an additional instance and therefore invoking someMethod() on this second instance will be the invocation of a second someMethod() method - defined at the second object. This is because you instantiate objects before use so all instances follow the blueprint FooBar defined. All instances therefore receive some kind of copy of someMethod().

(In practice Python will use optimizations internally, so there actually is only one piece of code that implements your someMethod() in memory, but forget about this for now. To a programmer it appears as that every instance of a class will have a copy of the method someMethod(). And that's the level of abstraction that is relevant to us as this is the "surface" we work on. Deep within the implementation of a programming or script language things might be a bit different but this is not very relevant.)

Let's have a look at a static method:

class FooBar:

@staticmethod
def someStaticMethod():
print("abc")

Such static methods can be invoked like this:

FooBar.someStaticMethod()

As you can see: No instance. You directly invoke this method in the context of the class itself. While regular methods work on the particular instance itself - they typically modify data within this instance itself - a class method does not. It could modify static (!) data, but typically it does not anyway.

Consider a static method a special case. It is rarely needed. What you typically want if you write code is not to implement a static method. Only in very specific situations it makes sense to implement a static method.

The self parameter

Please note that a standard "instance" method always must have self as a first argument. This is a python specific. In the real world Python will (of course!) store your method only once in memory, even if you instantiate thousands of objects of your class. Consider this an optimization. If you then invoke your method on one of your thousands of instances, always the same single piece of code is called. But for it to distinguish on which particular object the code of the method should work on your instance is passed to this internally stored piece of code as the very first argument. This is the self argument. It is some kind of implicit argument and always needed for regular (instance) methods. (Not: static methods - there you don't need an instance to invoke them).

As this argument is implicit and always needed most programming languages hide it to the programmer (and handle this internally - under the hood - in the correct way). It does not really make much sense to expose this special argument anyway.

Unfortunately Python does not follow this principle. Python does not hide this argument which is implicitly required. (Python's incorporation of OOP concepts is a bit ... simple.) Therefore you see self almost everywhere in methods. In your mind you can ignore it, but you need to write it explicitly if you define your own classes. (Which is something you should do in order to structure your programs in a good way.)

The static method __new__()

Python is quite special. While regular programming languages follow a strict and immutable concept of how to create instances of particular classes, Python is a bit different here. This behavior can be changed. This behavior is implemented in __new__(). So if you do this ...

myObj = FooBar()

... Python implicitly invokes FooBar.__new__() which in turn invokes a constructor-like (instance) method named __init__() that you could (!) define in your class (as an instance method) and then returns the fully initialized instance. This instance is then what is stored in myObj in this example her.

You could modify this behavior if you want. But this would requires a very very very particularly unusual use case. You will likely never have anything to do with __new__() itself in your entire work with Python. My advice: If you're somehow new to Python just ignore it.

Difference between @staticmethod and @classmethod

Maybe a bit of example code will help: Notice the difference in the call signatures of foo, class_foo and static_foo:

class A(object):
def foo(self, x):
print(f"executing foo({self}, {x})")

@classmethod
def class_foo(cls, x):
print(f"executing class_foo({cls}, {x})")

@staticmethod
def static_foo(x):
print(f"executing static_foo({x})")

a = A()

Below is the usual way an object instance calls a method. The object instance, a, is implicitly passed as the first argument.

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>, 1)

With classmethods, the class of the object instance is implicitly passed as the first argument instead of self.

a.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)

You can also call class_foo using the class. In fact, if you define something to be
a classmethod, it is probably because you intend to call it from the class rather than from a class instance. A.foo(1) would have raised a TypeError, but A.class_foo(1) works just fine:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)

One use people have found for class methods is to create inheritable alternative constructors.


With staticmethods, neither self (the object instance) nor cls (the class) is implicitly passed as the first argument. They behave like plain functions except that you can call them from an instance or the class:

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

Staticmethods are used to group functions which have some logical connection with a class to the class.


foo is just a function, but when you call a.foo you don't just get the function,
you get a "partially applied" version of the function with the object instance a bound as the first argument to the function. foo expects 2 arguments, while a.foo only expects 1 argument.

a is bound to foo. That is what is meant by the term "bound" below:

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

With a.class_foo, a is not bound to class_foo, rather the class A is bound to class_foo.

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

Here, with a staticmethod, even though it is a method, a.static_foo just returns
a good 'ole function with no arguments bound. static_foo expects 1 argument, and
a.static_foo expects 1 argument too.

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

And of course the same thing happens when you call static_foo with the class A instead.

print(A.static_foo)
# <function static_foo at 0xb7d479cc>

Static class variables and methods in Python

Variables declared inside the class definition, but not inside a method are class or static variables:

>>> class MyClass:
... i = 3
...
>>> MyClass.i
3

As @millerdev points out, this creates a class-level i variable, but this is distinct from any instance-level i variable, so you could have

>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)

This is different from C++ and Java, but not so different from C#, where a static member can't be accessed using a reference to an instance.

See what the Python tutorial has to say on the subject of classes and class objects.

@Steve Johnson has already answered regarding static methods, also documented under "Built-in Functions" in the Python Library Reference.

class C:
@staticmethod
def f(arg1, arg2, ...): ...

@beidy recommends classmethods over staticmethod, as the method then receives the class type as the first argument.

Python when to use instance vs static methods

The functions you have wrote in your code are instance methods but they were written incorrectly.
An instance method must have self as first parameter

i.e def build_url(self, url_paramater1, url_parameter2, request_date):

Then you call it like that

get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)

This self parameter is provided by python and it allow you to access all properties and functions - static or not - of your Get class.

If you don't need to access other functions or properties in your class then you add @staticmethod decorator and remove self parameter

@staticmethod
def build_url(url_paramater1, url_parameter2, request_date):

And then you can call it directly

Get.build_url(url_paramater1, url_parameter2, request_date)

or call from from class instance

get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)

But what is the problem with your current code you might ask?
Try calling it from an instance like this and u will see the problem

get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)

Example where creating an instance is useful:
Let's say you want to make a chat client.

You could write code like this

class Chat:
def send(server_url, message):
connection = connect(server_url)
connection.write(message)
connection.close()

def read(server_url):
connection = connect(server_url)
message = connection.read()
connection.close()
return message

But a much cleaner and better way to do it:

class Chat:

def __init__(server_url):
# Initialize connection only once when instance is created
self.connection = connect(server_url)

def __del__()
# Close connection only once when instance is deleted
self.connection.close()

def send(self, message):
self.connection.write(message)

def read(self):
return self.connection.read()

To use that last class you do

# Create new instance and pass server_url as argument
chat = Chat("http://example.com/chat")
chat.send("Hello")
chat.read()
# deleting chat causes __del__ function to be called and connection be closed
delete chat

What's the point of @staticmethod in Python?

Here is a post on static methods. In summary:

  • instance methods: require the instance as the first argument
  • class methods: require the class as the first argument
  • static methods: require neither as the first argument

Examples

It may be more clear to see how these work when called with arguments. A modified example:

class TestClass:

weight = 200 # class attr

def __init__(self, size):
self.size = size # instance attr

def instance_mthd(self, val):
print("Instance method, with 'self':", self.size*val)

@classmethod
def class_mthd(cls, val):
print("Class method, with `cls`:", cls.weight*val)

@staticmethod
def static_mthd(val):
print("Static method, with neither args:", val)

a = TestClass(1000)

a.instance_mthd(2)
# Instance method, with 'self': 2000

TestClass.class_mthd(2)
# Class method, with `cls`: 400

a.static_mthd(2)
# Static method, with neither args: 2

Notes

Overall, you can think of each method in terms of access:

  • If you need to access the instance or an instance component (e.g. an instance attribute), use an instance method as it passes self as the first argument.
  • Similarly, if you need to access a class, use a class method.
  • If access to neither an instance nor class is important, you can use a static method.

In the example above, the same argument is passed for each method type, but access to instance and class attributes differ through self and cls respectively.

Note, there is a way to access class components from an instance method by using self.__class__, thereby obviating the need for a class method:

    ...

def instance_mthd2(self, val):
print("Instance method, with class access via `self`:", self.__class__.weight*val)
...

a.instance_mthd2(2)
# Instance method, with class access via `self`: 400

Regarding your questions:

  1. Yes. While the variable name self is a convention, it pertains to the instance.
  2. Static methods can be used to group similar utility methods under the same class.
  3. For methods within a class, you either need to add self as the first argument or decorate the method with @staticmethod. "Non-decorated methods" without arguments will raise an error.

See Also

  • R. Hettinger's talk Python's Class Development Toolkit - explains the purpose for each method type clearly with examples.

What is the advantage of using static methods?

Static methods have limited use, because they don't have access to the attributes of an instance of a class (like a regular method does), and they don't have access to the attributes of the class itself (like a class method does).

So they aren't useful for day-to-day methods.

However, they can be useful to group some utility function together with a class - e.g. a simple conversion from one type to another - that doesn't need access to any information apart from the parameters provided (and perhaps some attributes global to the module.)

They could be put outside the class, but grouping them inside the class may make sense where they are only applicable there.

You can also reference the method via an instance or the class, rather than the module name, which may help the reader understand to what instance the method is related.

Calling static method in python

You need to do something like:

class Person:
@staticmethod
def call_person():
print("hello person")

# Calling static methods works on classes as well as instances of that class
Person.call_person() # calling on class
p = Person()
p.call_person() # calling on instance of class

Depending on what you want to do, a classmethod might be more appropriate:

class Person:
@classmethod
def call_person(cls):
print("hello person", cls)

p = Person().call_person() # using classmethod on instance
Person.call_person() # using classmethod on class

The difference here is that in the second example, the class itself is passed as the first argument to the method (as opposed to a regular method where the instance is the first argument, or a staticmethod which doesn't receive any additional arguments).

Now to answer your actual question. I'm betting that you aren't finding your method because you have put the class Person into a module Person.py.

Then:

import Person  # Person class is available as Person.Person
Person.Person.call_person() # this should work
Person.Person().call_person() # this should work as well

Alternatively, you might want to import the class Person from the module Person:

from Person import Person
Person.call_person()

This all gets a little confusing as to what is a module and what is a class. Typically, I try to avoid giving classes the same name as the module that they live in. However, this is apparently not looked down on too much as the datetime module in the standard library contains a datetime class.

Finally, it is worth pointing out that you don't need a class for this simple example:

# Person.py
def call_person():
print("Hello person")

Now in another file, import it:

import Person
Person.call_person() # 'Hello person'

Python: separate utilities file or use static methods?

You can achieve both 2 and 3 with this example of adding a static method to your class that is defined in a separate file.

helper.py:

def square(self):
self.x *= self.x

fitter.py:

class Fitter(object):
def __init__(self, x: int):
self.x = x
from helper import square

if name == '__main__':
f = Fitter(9)
f.square()
print(f.x)

Output:

81

Adapted from this answer which was doing this for a class method. Seems to work for static method, too.



Related Topics



Leave a reply



Submit