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?
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.
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.
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.
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.
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]
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With