Assign an external function as staticmethod in Python - python

I have a module, that contains a bunch of functions that generate xml's
In other module I am constructing a class, and I want to assign one of those function to a class variable
Problem is, the fuction acts as a class method and when i call it from another class method, it passes self as a first argument.
Did i choose a good design approach? How to avoid passing self to a function? (#staticmethod decorator before generate = gen.generate doesn't work)
I would like to avoid making a class out of generate function if possible
Thanks!
generators.py
def generate(id, date):
pass
def generate_another():
pass
main.py
import generators as gen
class Client():
generate = gen.generate
def get_result(self, *args, **qwargs):
request = self.generate(id, date)

You must understand, that:
#decorator
def some_func():
pass
Is just syntactic sugar for
def some_func():
pass
some_func = decorator(some_func)
So in this case, you just want:
import generators as gen
class Client:
generate = staticmethod(gen.generate)
def get_result(self, *args, **qwargs):
request = self.generate(id, date)
As to whether or not this is a good design decision, it's probably too much of an opion-based question. Personally, I tend to avoid staticmethod. What advantage does this design offer over simply calling gen.generate inside get_result?

This is nearly a duplicate of #juanpa.arrivillaga's answer, but with a simplification which highlights a potential design advantage, addressing Juanpa's question in the case where we're truly using a static method (no self arg needed).
Code which originally looks like this (class with a decorated static method)...
import generators as gen
class Client:
#staticmethod
def get_result(*args, **qwargs):
request = gen.generate(id, date)
... could be simplified as:
import generators as gen
class Client:
get_result = staticmethod(gen.generate)
In Juanpa's answer, the class has two ways of calling the same underlying gen.generate:
client = Client()
# 1. as a class method
client.get_result()
# 2. as a static method
client.generate()
This all neglects the details of what is done with the request object etc, but if the same external function can be recycled completely as a staticmethod in multiple classes, Juanpa's answer helps keep static methods DRY:
def recycled_function(some_arg):
...
class ClassOne:
static_func = staticfunction(recycled_function)
class ClassTwo:
static_func = staticfunction(recycled_function)
This approach is more concise than copying the full implementation of recycled_function into each class decorated by #staticmethod, or even by making a wrapper method or static function to call the external recycled_function.

Related

How to pass class attributes into method decorators?

I am trying to make a class that will make api requests, retrying based on configuration options passed in to the retrying.retry decorator, and handle different error codes in the correct way for each job.
Here is my code:
from retrying import retry
class APIRequester:
def __init__(self, url, **kwargs):
self.url = url
self.retry_kwargs = kwargs
#retry(**self.retry_kwargs) # Obviously doesn't know what self is
def make_request(self):
pass
How can I pass in parameters to this method decorator? I tried making them a class attribute, which didn't work either.
A couple of notes/questions:
The #retry decorator will be applied to the make_request method at the time the class is created, while retry_kwargs will only become available when an instance of the class is created, and thus the former must precede the latter.
In which case, the former cannot depend on information that becomes available in the latter, ... as long as you use the decorator syntax ...
The decorator syntax
#decorator
def xxx(...):
...
is just syntax sugar for
def xxx(...):
...
xxx = decorate(xxx)
which means that, along with the fact that Python is very dynamic, you could force the issue by doing something like
class APIRequester:
def __init__(self, url, **kwargs):
self.url = url
self.retry_kwargs = kwargs
APIRequester.make_request = retry(**kwargs)(APIRequester.make_request)
def make_request(self):
pass
Whether this particular decorator chokes on the self parameter or not, I cannot tell you.
Will you have more than one instance of APIRequester? If so, note that the method will be re-decorated each time a new instance is created: can this work sensibly? (I doubt it.) But see the edit below ...
If you do not have more that one instance, then you probably don't need to rely on information that becomes availale at the singleton's construction time.
The above were some general Python principles. I doubt that you really want to force the issue in this case. It seems to me that you are trying to use the decorator in a way that it was not designed to be used.
Edit: instancemethods
If you replace the line that does the decorating in the constructor with
self.make_request = retry(**kwargs)(self.make_request)
then each instance will get its own decorated version of the function. This should avoid any problems with re-decoration of the same function. There may will still be problems with self getting in the way. In that case, you could remove the self parameter from the definition and wrap it with staticmethod:
self.make_request = retry(**kwargs)(staticmethod(self.make_request))
Or better still, use decorator syntax to apply staticmethod to make_request at the place where you define it, the way Guido inteded it.
Like this, it even stands a chance of working! :-)
Decorator is just a syntax sugar for func=decorator(func). You can do the assignment yourself:
class APIRequester:
def __init__(self, url, **kwargs):
self.url = url
self.make_request = retry(**kwargs)(self.make_request)
def make_request(self):
pass
This will internally replace a method (descriptor) by a function, but it will work as expected.
Of course self is available in the decorator at the call time. See answers to How to decorate a method inside a class? , on which I based my answer here:
def my_retry(fn):
from functools import wraps
#wraps(fn)
def wrapped(self):
print(self.retry_kwargs)
for i in range(self.retry_kwargs["times"]):
# you have total control
fn(self)
# around your method. Can even call it multiple times,
# call with original retry:
retry(**self.retry_kwargs)(fn)(self)
# check exceptions, return some value (here None), etc
#
return wrapped
class APIRequester(object):
def __init__(self, url, **kwargs):
self.url = url
self.retry_kwargs = kwargs
#my_retry
def make_request(self):
print("method")
a = APIRequester('http://something', times=3)
a.make_request()
That is, original decorator is wrapped with a new, configuration-aware decorator. No need to change the constructor, syntax remains simple.
Retry decorator doesn't support class method, because instance of the class is implicitly passed to function.
Please decorate normal function.
If you want to wrap function into class, please decorate static method.

Python - staticmethod vs classmethod

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.

Reference class from #staticmethod

↑↑↑ It does NOT
Let's say I have a class with some utility methods:
class Utils:
#staticmethod
def do_stuff():
# some stuff
Utils.do_other_stuff()
# some more stuff
#staticmethod
def do_other_stuff():
# somehting other
I don't really like the Utils.do_other_stuff() part.
If it was instance method, I would reference it via self, but here I have to write the full class name.
Is this where #classmethod is a good idea to use, or is it overkill? - or is there some cleaner way to write Utils, perhaps with a module?
If you need a reference to the current class (which could be a subclass), then definitely make it a classmethod.
That's not overkill; the amount of work Python does to bind a class method is no different from a static method, or a regular method for that matter.
However, don't use classes here unless you have to. Python is not Java, you do not have to use a class and functions can live outside of classes just fine.
#classmethod is the way to go:
class Utils:
#classmethod
def do_stuff(cls):
# some stuff
cls.do_other_stuff()
# some more stuff
#classmethod
def do_other_stuff(cls):
# somehting other
Just a clarification related to Martijn Pieters comment: I usually avoid #staticmethod and I prefer to adopt always #classmethod because it allows me to refer to the class and its methods. (I don't agree with suggestions about writing modules with functions… I'm an OOP supporter :P)
It doesn't look like Utils will ever be subclassed or instantiated; it's just a wrapper for static methods. In that case, these methods can all be turned into module-level functions, perhaps in a separate utils module:
# No class!
def do_stuff():
...
do_other_stuff()
...
def do_other_stuff():
...

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 possible in Python to decorate a method in class using method in instance

I'm trying to wrap a function when defining the class, use method in this class's instance
Below is a code that works
class A(object):
def __init__(self):
pass
#self_decorator
def to_be_decorated(self):
pass
def self_decorator(fn):
from functools import wraps
#wraps(fn)
def wrapper(*args, **kwargs):
self = args[0]
return self.app.route('/twip')(fn(*args, **kwargs))
return wrapper
What I actually tries to get:
class A(object):
def __init__(self):
self.app = APP()
#self.app.wrapper_function # which apparently doesn't work
def to_be_decorated(self):
pass
So, is it possible for my way of decorating to work?
At the class definition there's no self as the class do not exists yet and cannot be instantiated.
You can use
class A(object):
app = APP()
#app.wrapper_function
def to_be_decorated(self):
pass
But that would be a class variable.
A decorator is just a function that gets called at the time of definition.
When you write this:
#self.app.wrapper_function # which apparently doesn't work
def to_be_decorated(self):
pass
it's roughly the same as writing this:
def to_be_decorated(self):
pass
to_be_decorated = self.app.wrapper_function(to_be_decorated)
Once you see it that way, it's obvious why this doesn't work, and couldn't possibly work.
First, A's class definition doesn't have a self variable, nor does A have a member app that could be accessed even if it did. Instead, each instance of A will have its own unique self.app.
And even if you wish the interpreter could just "do what I mean", if you think about it, that can't mean anything. You want to call "the" self.app.wrapper_function method, but there is no such thing. Unless you read through all of the relevant code everywhere the method could be defined or redefined, there's absolutely no guarantee that the self.app.wrapper_function from different instances of A will even have the same underlying func_code. But, even if they did, self.app.wrapper_function is a bound method—a method bound together with the object it's called on—so they're still all different from each other.
There are plenty of ways around this, but they're all going to be the same trick: Use some kind of indirection to get a function which isn't a member of self.app or self, and references self.app at call time. This is basically what your self_decorator does, and it's unavoidable.

Categories

Resources