[英]What is the most pythonic way to reuse data in multiple calls to same function?
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 (eg list comprehension vs map, filter). 通常我不会问这样的问题,但是python似乎有1.一个不同寻常的社区对习语的共识,并且通过使它们更具性能来鼓励它们(例如列表理解与地图,过滤器)。
This is a pattern I find myself using quite a bit when coding, consider the following JavaScript: 这是我在编码时发现自己使用的模式,请考虑以下JavaScript:
var f = (function() {
var closedOver = "whatever"
return function(param) {
// re-uses closure variable again and again with different param
}
})();
Or C: 或者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: 一些可能的方法转换为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. 我也可以通过重新实例化每次通话来“解决”这个问题,并希望它会被优化掉,但由于我没有使用pypy,我对这个得分并不太有希望。
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.)?
第二,如果没有,上面哪个是最“pythonic”(惯用,高性能,合理等)?
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.
但是,我同意你的看法:随着时间的推移,Python社区确实倾向于与许多实现问题保持一致。 That's one of the strengths of Python.
这是Python的优势之一。
Here's my rule of thumb: When in doubt, try to use the Python standard library as much as possible. 这是我的经验法则:如有疑问,请尽量使用Python标准库。 Your instinct here about
functools.partial
is correct, for these reasons: 你对
functools.partial
直觉是正确的,原因如下:
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. 您的dict(或列表,或任何可变的)绑定到函数对象。 Subsequent calls, when cache keyword argument is omitted, will refer to same object.
当省略cache关键字参数时,后续调用将引用同一对象。 This object state will persist across calls.
此对象状态将在调用之间保持不变。
I don't like idea with var in outer scope and may suggest use closure, I think it's better way, as you see it's more like JavaScript, so you can work with functions as objects : 我不喜欢外部范围的var的想法,可能建议使用闭包,我认为这是更好的方式,因为你看它更像JavaScript,所以你可以使用函数作为对象:
def foo():
const = 1
def bar(param):
return const + param
return bar
a = foo()
print(a(5))
There is an alternative that you didn't mention, which is IMO the most pythonic way which wouldn't create a throw away name :) 还有一个你没有提到的替代方案,这是IMO最狡猾的方式,它不会创造一个扔掉的名字:)
def foo(variant):
try:
return foo.invariant + variant
except AttributeError:
foo.invariant = 1
return foo(variant)
Although, sticking with the std library would be the best. 虽然坚持使用std库是最好的。
I don't think your two first examples are equivalent. 我不认为你的两个第一个例子是等价的。 The first seems to be a closure, while the second uses a global constant.
第一个似乎是闭包,而第二个使用全局常量。 Anyway, for the first example, a direct equivalent in python would be
无论如何,对于第一个例子,python中的直接等价物将是
def f(x):
def g(y):
return x + y
return g
and use it like 并使用它
add2 = f(2)
print(add2(3)) # == 5
Actually, your implementation using partial
, does something similar under the hood 实际上,你的实现使用
partial
,在引擎盖下做了类似的事情
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.