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开发者_如何学JAVA 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?
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]
.
Decorators extend the functionality of the function it decorates in a generic way. If decorators to do not make any assumption about the function or it's args or kwargs, it is in most generic form and can be easily used with many functions.
How ever, if you want to do something with what is being passed onto the function, it should be fine but their applicability is limited and can break, if the underlying details, which you have used in your decorator changes.
In the above decorator, if the object removes the method get_undo_token(), you will need to revisit the decorator too. It is fine to do that but document the constraints and also add that documentation to the method doc it self.
Do it only if absolutely necessary. It serves to create more generic decorators.
精彩评论