2

I want to decorate a class method, but can't quite figure out how to do it. Minimal class example:

class Circle(object): def __init__(self,radius): self.R = radius def arc_length(self,theta): return self.R*theta 

Now let's say I want another method which takes the arc_length always relative to some particular other value of arc length so I define a function as follows:

def relative(rel_val): def decorator(fn): def wrapper(*args): return fn(*args) - fn(rel_val) return wrapper return decorator 

so now I extend my class to:

class Circle(object): def __init__(self,radius): self.R = radius def arc_length(self,theta): return self.R*theta @relative(0.2) def relative_arc_length(self,theta): return self.arc_length(theta) 

I would hope this would give the desired behaviour, but I get error: relative_arc_length() takes exactly 2 arguments (1 given)

I assume this is something to do with the self argument, but if I add self to the fn(self,rel_val) in the relative definition it gives me: global name "self" is not defined

So how do I fix this? Interestingly, if I do the following:

c = Circle(10) relative(0.2)(c.arc_length)(1.5) 

it works as expected.

Can anyone point me to where I'm going wrong? Also, is it possible to define the decorated function inside the class, and if so, should I do this? Is it good programming practice?

1 Answer 1

2
return fn(*args) - fn(rel_val) 

Methods are always called with self as the first parameter. So in your case, you are passing all arguments just fine to the first call, but forget the self in the second call.

You will have to extract self from args and pass that too:

obj, value = args return fn(obj, value) - fn(obj, rel_value) 

You should probably include a check to ensure that there are only exactly two values in args at any time too, so you don’t accidentally use the decorator for incompatible methods.

Sign up to request clarification or add additional context in comments.

1 Comment

Great answer. It took me some time to realize that there was nothing wrong with writing fn(*args) in the return statement (rewriting it to fn(obj, value) makes no difference); the error came from fn(rel_val) as this was missing the underlying object as the first parameter

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.