Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it bad practice to use self in decorators?

While I'm aware that you can't reference self directly in a decorator, I was wondering if it's bad practice to work around that by pulling it from args[0]. My hunch is that it is, but I want to be sure.

To be more specific, I'm working on an API to a web service. About half the commands require a token to be passed that can be later used to undo it. What I would like is to make that token an optional parameter and if none is supplied, to generate one. Generating a token requires making an authenticated call to the server, which needs data from the object.

While I know I could do it:

def some_command(self, ..., undo_token = None):
    if undo_token = None:
        undo_token = self.get_undo_token()
    ...
    return fnord

I feel like there could be a better way than to have the same code in a dozen or so methods. My thought was to write a decorator:

@decorator
def undoable(fn, *args, **kwargs):
    if 'undo_token' not in kwargs:
        kwargs['undo_token'] = args[0].get_undo_token()
    return (fn(*args, **kwargs), kwargs['undo_token'])

So I can more cleanly write

@undoable
def some_command(self, ...):
    ...
    return foo

@undoable
def some_other_command(self, ...):
    ...
    return bar

Am I setting myself up for trouble down the line?

like image 998
michael Avatar asked Sep 02 '10 22:09

michael


People also ask

Which of the following is true about decorators?

Decorators can be chained A Decorator function is used only to format the output of another function dec keyword is used for decorating a function Decorators always return None” Code Answer.

What is the point of decorators?

A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.

Does order of decorators matter Python?

The Flask documentation specifies that the order matters if the function is a view and has a route decorator. From the docs: When applying further decorators, always remember that the route() decorator is the outermost. Save this answer.

Can decorator return value?

Return values from decorated functions don't get returned by default unless the decorator allows it. In this lesson, you'll see how to get return values out of decorated functions by making a small change to the decorator.


1 Answers

I don't understand what you're coding for undoable -- that's not how decorators are normally coded and I don't know where that @decorator is coming from (is there a from youforgottotelluswhence import decorator or something even more evil? see why I can't stand the use of from to build "artificial barenames" instead of using nice decorated names?-).

With normal decorator coding, e.g....:

import functools

def undoable(f):
    @functools.wraps(f)
    def wrapper(self, *a, **k):
        tok = k.get('undo_token')
        if tok is None:
            tok = k['undo_token'] = self.get_undo_token()
        return f(self, *a, **k), tok
    return wrapper

there's absolutely no problem naming the wrapper's first, mandatory positional argument self, and much gain of clarity in using this rather than the less-readable args[0].

like image 183
Alex Martelli Avatar answered Sep 19 '22 13:09

Alex Martelli