Normally I would not ask such a question, but python seems to have 1. an unusual level of community consensus on idioms and 2. tends to encourage them by making them more performant (e.g. list comprehension vs map, filter).
This is a pattern I find myself using quite a bit when coding, consider the following JavaScript:
var f = (function() {
var closedOver = "whatever"
return function(param) {
// re-uses closure variable again and again with different param
}
})();
Or C:
int foo(int x)
{
/*
compile-time constant, will not be recalced for every call,
name 'someConst' not visible in other scopes
*/
const int someConst = 134;
/* do stuff */
return whatever;
}
Some possible ways to translate into python:
globalConstant = someConstant
def foo(param):
# does stuff with param and constant
return whatever
or possibly:
from functools import partial
def foo(invariant, variant):
"""Actually bar"""
# does stuff
return whatever
bar = partial(foo, someInvariant)
or:
class Foo(object):
"""I'm just here to hold a non-visible binding. Actually bar"""
def __init__(self, invariant):
super(Foo, self).__init__()
self.value = invariant
def __call__(self, param):
return actualFnResultWithSelfValue
bar = Foo(invariant)
or:
def foo(variant, invariant=someConstantValue):
return whatever
This is unfortunate, now depending on which way I go I may have to use a throw-away name for the initial function definition since I'm only ever using the partially applied version, write a lot of boilerplate classes (which also have throw-away names), or pollute the module namespace with a global constant when its only used in one function, or restrict my function parameters and ensure that someone can break it by calling it with the wrong number of arguments.
I could also 'solve' this by re-instantiating on every call and hoping that it will get optimized away, but since I'm not using pypy I'm not too hopeful on that score.
So my question is two-fold: first, is there a way to do this without the trade-offs? And second, if not, which of the above is the most 'pythonic' (idiomatic, performant, reasonable, etc.)?
Jared, I totally understand your hesitation to ask this, because it could be answered by many different opinions and spawn a flame war. But, I do agree with your observation: the Python community does tend towards consistency over time with many implementation questions. That's one of the strengths of Python.
Here's my rule of thumb: When in doubt, try to use the Python standard library as much as possible. Your instinct here about functools.partial
is correct, for these reasons:
I hope that helps!
I'd suggest something that's usually a code smell - default mutable argument.
Trivial example:
def f(x, cache={'x': 0}):
cache['x'] += x;
return cache['x']
assert f(1) == 1
assert f(1) == 2
assert f(1) == 3
assert f(3) == 6
Your dict (or list, or anything which is mutable) is bound to function object. Subsequent calls, when cache keyword argument is omitted, will refer to same object. This object state will persist across calls.
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