Python - staticmethod vs classmethod - python

I've a class which returns the health statistics of the machine.
class HealthMonitor(object):
"""Various HealthMonitor methods."""
#classmethod
def get_uptime(cls):
"""Get the uptime of the system."""
return uptime()
#classmethod
def detect_platform(cls):
"""Platform detection."""
return platform.system()
#classmethod
def get_cpu_usage(cls):
"""Return CPU percentage of each core."""
return psutil.cpu_percent(interval=1, percpu=True)
#classmethod
def get_memory_usage(cls):
"""Return current memory usage of a machine."""
memory = psutil.virtual_memory()
return {
'used': memory.used,
'total': memory.total,
'available': memory.available,
'free': memory.free,
'percentage': memory.percentage
}
#classmethod
def get_stats(cls):
return {
'memory_usage': cls.get_memory_usage(),
'uptime': cls.uptime(),
'cpu_usage': cls.get_cpu_usage(),
'security_logs': cls.get_windows_security_logs()
}
Method get_stats will be called from outside the class. Which is the correct way to defining the related functions. Using classmethods or staticmethods or make an object of the class and then call the get_stats.
I've read enough on the differences, but still want to clear my understanding with an example. Which is the more pythonic approach?

Use #classmethod when the method needs class information, i.e accessing class attributes. (let's say the health_monitor class had OS attribute, which would affect the command you execute)
Use #staticmethod when the method doesn't need any data of the class it is declared in; like all your functions.
I often find myself use staticmethod for functions I put inside a class for simplicity, because they are running in context with my class, but not rely on it.
As for your class: when all your methods are classmethods or staticmethods, you should consider reside the code in a module scope and not a class. Why? well, there is no reason to group them in a class if they don't share any data between them. It would be just more simple:
# health_monitor.py
def get_uptime(cls):
"""Get the uptime of the system."""
return uptime()
# main.py
health_monitor.get_uptime()

Well, classes basically provide an encapsulation over data i.e. a set of behaviour over certain data that identifies that object. Now, none of the methods that you have defined have anything to do with the class in particular.
Therefore, as long as you don't need to share data between those methods, it doesn't make sense at all to use classmethods. Although you'd be better off using static methods instead, then again all they would do is just provide a namespace. How about just defining all the methods as simple functions in a file named health_monitor.py, and then using it as follows -
import health_monitor
uptime = health_monitor.get_uptime()
Only con of this approach is that you'd have to enforce this convention of importing by the module name and not function.

Related

#staticmethod or function outside class?

Assuming I have a class which requires a function (or should I say method) which is:
independent from my class instance - doesn't need self argument;
is called only inside my class object
I won't need access to it at any point (to override it for example);
should I (A) place it inside the class and mark it as a #staticmethod or should I (B) define it outside my class object (but in the same namespace)? Why?
Example:
class A:
def __init__(self, my_int):
self.my_int = my_int
def my_int_and_4(self):
print(self.adder(self.my_int,4))
#staticmethod
def adder(a,b):
return a+b
or
def adder(a,b):
return a+b
class B:
def __init__(self, my_int):
self.my_int = my_int
def my_int_and_4(self):
print(adder(self.my_int,4))
EDIT: maybe the example is a bit oversimplified. I should have added that my version of "adder" is specificly used with my class and in no other case.
This is a textbook use case for a private static method.
They key point here is that you should make it a private method of that class. That way you're certain nothing else will use it and depend on its implementation. You'll be free to change it in the future, or even delete it, without breaking anything outside that class.
And yeah, make it static, because you can.
In Python, there is no way to make a method truly private, but by convention, prefixing the method name by a _ means it should be treated as private.
#staticmethod
def _adder(a,b): ## <-- note the _
return a+b
If at some point you suddenly need to use it outside the class, then exposing it will be no trouble at all, e.g. using a public wrapper method.
The reverse, however, isn't true; once exposed, it's difficult to retract that exposure.
I would definitely use a private static method in this case, for the reasons described by Jean-Francois Corbett. There are two types of methods in Python that belong to the class itself, rather than an instance: class methods and static methods.
The first parameter of a class method (created with #classmethod) references the class in exactly the same manner that the first parameter of an instance method (self) references an instance. It is the equivalent of static methods in most other languages. If your method requires access to other class members, use a class method.
A static method (created with #staticmethod) does not contain a reference to the class, and therefore cannot reference other class members. It's generally used for private helper methods and the like.
For your adder method, I would definitely use a static method. However, in this modified (and rather useless) version, a class method is necessary:
class A:
x = 1
def __init__(self, my_int):
self.my_int = my_int
def my_int_and_4(self):
print(self._adder(self.my_int,4))
#staticmethod
def _adder(a,b):
return a+b
#classmethod
def _increment(cls, n):
return n + cls.x
Both approaches will work, so it's the matter of readability and following conventions.
Does the method need to look at the instance's private attributes? If yes, it's a good reason to keep it in the class.
Is the method only used as a helper for one of different methods? If yes, it's a good reason to put it right after the calling method so that the code can be read top-down.
Does the method seem to make sense outside of the context of your class? If yes, it's a good reason to make it a free function or even move it to a different file, like utils.

Benefit of using custom initialize function instead of `__init__` in python

I was looking into the following code.
On many occasions the __init__ method is not really used but there is a custom initialize function like in the following example:
def __init__(self):
pass
def initialize(self, opt):
# ...
This is then called as:
data_loader = CustomDatasetDataLoader()
# other instance method is called
data_loader.initialize(opt)
I see the problem that variables, that are used in other instance methods, could still be undefined, if one forgets to call this custom initialize function. But what are the benefits of this approach?
Some APIs out in the wild (such as inside setuptools) have similar kind of thing and they use it to their advantage. The __init__ call could be used for the low level internal API while public constructors are defined as classmethods for the different ways that one might construct objects. For instance, in pkg_resources.EntryPoint, the way to create instances of this class is to make use of the parse classmethod. A similar way can be followed if a custom initialization is desired
class CustomDatasetDataLoader(object):
#classmethod
def create(cls):
"""standard creation"""
return cls()
#classmethod
def create_with_initialization(cls, opt):
"""create with special options."""
inst = cls()
# assign things from opt to cls, like
# inst.some_update_method(opt.something)
# inst.attr = opt.some_attr
return inst
This way users of the class will not need two lines of code to do what a single line could do, they can just simply call CustomDatasetDataLoader.create_with_initialization(some_obj) if that is what they want, or call the other classmethod to construct an instance of this class.
Edit: I see, you had an example linked (wish underlining links didn't go out of fashion) - that particular usage and implementation I feel is a poor way, when a classmethod (or just rely on the standard __init__) would be sufficient.
However, if that initialize function were to be an interface with some other system that receives an object of a particular type to invoke some method with it (e.g. something akin to the visitor pattern) it might make sense, but as it is it really doesn't.

Why do we use #staticmethod?

I just can't see why do we need to use #staticmethod. Let's start with an exmaple.
class test1:
def __init__(self,value):
self.value=value
#staticmethod
def static_add_one(value):
return value+1
#property
def new_val(self):
self.value=self.static_add_one(self.value)
return self.value
a=test1(3)
print(a.new_val) ## >>> 4
class test2:
def __init__(self,value):
self.value=value
def static_add_one(self,value):
return value+1
#property
def new_val(self):
self.value=self.static_add_one(self.value)
return self.value
b=test2(3)
print(b.new_val) ## >>> 4
In the example above, the method, static_add_one , in the two classes do not require the instance of the class(self) in calculation.
The method static_add_one in the class test1 is decorated by #staticmethod and work properly.
But at the same time, the method static_add_one in the class test2 which has no #staticmethod decoration also works properly by using a trick that provides a self in the argument but doesn't use it at all.
So what is the benefit of using #staticmethod? Does it improve the performance? Or is it just due to the zen of python which states that "Explicit is better than implicit"?
The reason to use staticmethod is if you have something that could be written as a standalone function (not part of any class), but you want to keep it within the class because it's somehow semantically related to the class. (For instance, it could be a function that doesn't require any information from the class, but whose behavior is specific to the class, so that subclasses might want to override it.) In many cases, it could make just as much sense to write something as a standalone function instead of a staticmethod.
Your example isn't really the same. A key difference is that, even though you don't use self, you still need an instance to call static_add_one --- you can't call it directly on the class with test2.static_add_one(1). So there is a genuine difference in behavior there. The most serious "rival" to a staticmethod isn't a regular method that ignores self, but a standalone function.
Today I suddenly find a benefit of using #staticmethod.
If you created a staticmethod within a class, you don't need to create an instance of the class before using the staticmethod.
For example,
class File1:
def __init__(self, path):
out=self.parse(path)
def parse(self, path):
..parsing works..
return x
class File2:
def __init__(self, path):
out=self.parse(path)
#staticmethod
def parse(path):
..parsing works..
return x
if __name__=='__main__':
path='abc.txt'
File1.parse(path) #TypeError: unbound method parse() ....
File2.parse(path) #Goal!!!!!!!!!!!!!!!!!!!!
Since the method parse is strongly related to the classes File1 and File2, it is more natural to put it inside the class. However, sometimes this parse method may also be used in other classes under some circumstances. If you want to do so using File1, you must create an instance of File1 before calling the method parse. While using staticmethod in the class File2, you may directly call the method by using the syntax File2.parse.
This makes your works more convenient and natural.
I will add something other answers didn't mention. It's not only a matter of modularity, of putting something next to other logically related parts. It's also that the method could be non-static at other point of the hierarchy (i.e. in a subclass or superclass) and thus participate in polymorphism (type based dispatching). So if you put that function outside the class you will be precluding subclasses from effectively overriding it. Now, say you realize you don't need self in function C.f of class C, you have three two options:
Put it outside the class. But we just decided against this.
Do nothing new: while unused, still keep the self parameter.
Declare you are not using the self parameter, while still letting other C methods to call f as self.f, which is required if you wish to keep open the possibility of further overrides of f that do depend on some instance state.
Option 2 demands less conceptual baggage (you already have to know about self and methods-as-bound-functions, because it's the more general case). But you still may prefer to be explicit about self not being using (and the interpreter could even reward you with some optimization, not having to partially apply a function to self). In that case, you pick option 3 and add #staticmethod on top of your function.
Use #staticmethod for methods that don't need to operate on a specific object, but that you still want located in the scope of the class (as opposed to module scope).
Your example in test2.static_add_one wastes its time passing an unused self parameter, but otherwise works the same as test1.static_add_one. Note that this extraneous parameter can't be optimized away.
One example I can think of is in a Django project I have, where a model class represents a database table, and an object of that class represents a record. There are some functions used by the class that are stand-alone and do not need an object to operate on, for example a function that converts a title into a "slug", which is a representation of the title that follows the character set limits imposed by URL syntax. The function that converts a title to a slug is declared as a staticmethod precisely to strongly associate it with the class that uses it.

Python, executing extra code at method definition

I am writing a python API/server to allow an external device (microcontroller) to remotely call methods of an object by sending a string with the name of the method. These methods would be stored in a dictionary. e.g. :
class Server:
...
functions = {}
def register(self, func):
self.functions[func.__name__] = func
def call(self, func_name, args):
self.functions[func_name](*args)
...
I know that I could define functions externally to the class definition and register them manually, but I would really like that the registering step would be done automatically. Consider the following class:
class MyServer(Server):
...
def add(self,a,b):
print a+b
def sub(self,a,b):
print a-b
...
It would work by subclassing a server class and by defining methods to be called. How could I get the methods to be automatically registered in the functions dictionary?
One way that I thought it could be done is with a metaclass that look at a pattern in the methods name add if a match is found, add that methods to the functions dictionary. It seems overkill...
Would it be possible to decorate the methods to be registered? Can someone give me a hint to the simplest solution to this problem?
There is no need to construct a dictionary, just use the getattr() built-in function:
def call(self, func_name, args):
getattr(self, func_name)(*args)
Python actually uses a dictionary to access attributes on objects anyway (it's called __dict__, - but using getattr() is better than accessing it directly).
If you really want to construct that dict for some reason, then look at the inspect module:
def __init__(self, ...):
self.functions = dict(inspect.getmembers(self, inspect.ismethod))
If you want to pick specific methods, you could use a decorator to do that, but as BrenBarn points out, the instance doesn't exist at the time the methods are decorated, so you need to use the mark and recapture technique to do what you want.

Is it better to have standalone functions in globals or group them in a class?

I have inherited code in which there are standalone functions, one per country code. E.g.
def validate_fr(param):
pass
def validate_uk(param):
pass
My idea is to create a class to group them together and consolidate the code into one method. Unfortunately that breaks cohesion. Another option is to dispatch to instance methods ?
class Validator(object):
def validate(param, country_code):
# dispatch
Alas, python does not have a switch statement.
UPDATE: I am still not convinced why I should leave them as global functions in my module. Lumping them as class methods seems cleaner.
I would keep the functions at module level -- no need for a class if you don't want to instantiate it anyway. The switch statement can easily be simulated using a dicitonary:
def validate_fr(param):
pass
def validate_uk(param)
pass
validators = {"fr": validate_fr,
"uk": validate_uk}
def validate(country_code, param):
return validators[country_code](param)
Given the naming scheme, you could also do it without the dictionary:
def validate(country_code, param):
return gloabls()["validate_" + country_code](param)
You do not need a switch statement for this.
validators = {
'fr': Validator(...),
'uk': Validator(...),
...
}
...
validators['uk'](foo)
Classes are not meant to group functions together, modules are. Functions in a class should be either methods that operate on the object itself (changing it's state, emitting information about the state, etc.) or class methods that do the same, but for the class itself (classes in Python are also objects). There's not even a need for static methods in Python, since you can always have functions at module level. As they say: Flat is better than nested.
If you want to have a set of functions place them in separate module.

Categories

Resources