Milano
Milano

Reputation: 18745

Check whether method is a class method and call attribute

I built a little decorator for logging purposes.

def func_detail(func):
    def func_wrapper(*args,**kwargs):
        log(func.__name__+' ARGS: {}'.format(str(args)))
        return func(*args,**kwargs)
    return func_wrapper

This works for both object methods and normal methods. I want to use it in multithreading. I have a class which contains pid as an object attribute. Is it possible to change the decorator to log pid if it detects that the method belongs to some class and this class contains attribute pid?

I've tried:

def func_detail(func):
    def func_wrapper(*args,**kwargs):
        log('PID: '+self.pid if self.pid is not None else ' '+func.__name__+' ARGS: {}'.format(str(args)))
        return func(*args,**kwargs)
    return func_wrapper

But this not works at all. Could you help me?

ABSTRACT:

I want to be able to call attribute pid from the class where the method (func) belongs without passing self as an argument to the wrapper because in that case it would not works for methods which aren't inside a classes.

Upvotes: 0

Views: 95

Answers (2)

nameCensored
nameCensored

Reputation: 86

If you are calling a method, the object itself will be the first parameter, the self in the method implementation.

If your decorator was only applied to methods (defined as def methodName(self, ...):) you could capture the first parameter in self.

Then you could try to print self.pid and catch the exception if there isn't any such attribute.

Since there is little distinction between free functions and method, I think that you should define two decorators one for free function, and another for method, or define a decorator taking a parameter saying wether it is a method or not.

Another solution is to check if the args isn't empty and print args[0].pid if it exists.

Upvotes: 0

Blckknght
Blckknght

Reputation: 104762

The self argument to methods is not magically made available to your func_wrapper function in your decorator. Rather, it will be the first of the position arguments you're capturing with *args. If you want to make use of it, you'll need to examine args[0] and see if it has a pid attribute.

Try this, which checks first that a first argument exists, then that if it has a pid attribute:

log('{}FUNC: {} ARGS: {}'.format('PID: {} '.format(args[0].pid)
                                 if args and hasattr(args[0], "pid") else '',
                                 func.__name__, args))

Upvotes: 3

Related Questions