For me, a equally powerful AND readable way is to have named arguments with defaults. So when you change the function definition to add more arguments you can insert defaults so as not to break existing code.
For me, a equally powerful AND readable way is to have named arguments with defaults. So when you change the function definition to add more arguments you can insert defaults so as not to break existing code.
def trace(fn):
def worker(*args):
logging.info('Called %s with args %r', fn.__name__, args)
return fn(*args)
worker.__name__ = fn.__name__
# other decorator boilerplate
return worker
@trace
def foo(bar, baz):
...
@trace
def foo2(x1, x2, x3):
...
(Note that logging.info itself takes args & kwargs as its arguments, and passes them along as formatting arguments for the string.)If you've ever looked at AspectJ or even Haskell, this sort of functionality is virtually impossible in a statically-typed language. You go through all sorts of contortions to be able to say "I want to operate on any type of function, and I don't care how many or what type of arguments it has", and then come out with something insanely complicated that satisfies nobody. For certain use-cases, you really don't care what type of arguments it takes, you just want to pass it through to some other function.
I do wonder if there's some other language feature that could be used to achieve this without breaking documentation or static analysis, though.
def trace(fn):
@functools.wraps(fn)
def worker(*args):
logging.info('Called %s with args %r', fn.__name__, args)
return fn(*args)
return worker
Docs: http://docs.python.org/3/library/functools.html#functools.wr...In my experience, the best use for default arguments is when the API contract really does call for "default usage", but occasionally you need to pass an extra arg for special purposes. So if 95% of call sites only need n args but 1-2 of them need to vary a parameter or two of the algorithm, then defaults are appropriate. Passing the extra args by keyword usually ends up being much more readable in this case though.