簡體   English   中英

在多次調用同一函數時重用數據的最pythonic方法是什么?

[英]What is the most pythonic way to reuse data in multiple calls to same function?

通常我不會問這樣的問題,但是python似乎有1.一個不同尋常的社區對習語的共識,並且通過使它們更具性能來鼓勵它們(例如列表理解與地圖,過濾器)。

這是我在編碼時發現自己使用的模式,請考慮以下JavaScript:

var f = (function() {
  var closedOver = "whatever"
  return function(param) {
    // re-uses closure variable again and again with different param
  }
})();

或者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;
}

一些可能的方法轉換為python:

globalConstant = someConstant
def foo(param):
    # does stuff with param and constant
    return whatever

或者可能:

from functools import partial
def foo(invariant, variant):
    """Actually bar"""
    # does stuff
    return whatever

bar = partial(foo, someInvariant)

要么:

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)

要么:

def foo(variant, invariant=someConstantValue):
  return whatever

這是不幸的,現在取決於我走哪條路我可能不得不使用一個丟棄的名稱作為初始函數定義,因為我只使用部分應用的版本,寫了很多樣板類(也有拋出 - 當它僅在一個函數中使用時,或者使用全局常量污染模塊命名空間,或限制我的函數參數並確保有人可以通過使用錯誤數量的參數調用它來破壞它。

我也可以通過重新實例化每次通話來“解決”這個問題,並希望它會被優化掉,但由於我沒有使用pypy,我對這個得分並不太有希望。

所以我的問題有兩個方面:首先,有沒有辦法在沒有權衡的情況下做到這一點? 第二,如果沒有,上面哪個是最“pythonic”(慣用,高性能,合理等)?

賈里德,我完全明白你猶豫要問這個,因為它可以通過許多不同的意見來回答,並產生一場火焰戰爭。 但是,我同意你的看法:隨着時間的推移,Python社區確實傾向於與許多實現問題保持一致。 這是Python的優勢之一。

這是我的經驗法則:如有疑問,請盡量使用Python標准庫。 你對functools.partial直覺是正確的,原因如下:

  1. Python標准庫是高度優化的C代碼,它將超出您提出的任何Python類或函數閉包結構。
  2. Python標准庫被其他Python程序員廣泛使用,因此當您使用它時,其他Python程序員將更廣泛地理解您的編碼意圖。 (“代碼的讀取頻率高於編寫代碼。”)
  3. Python標准庫由核心Python開發人員編寫; 沒有代碼可能聲稱比標准庫更“Pythonic”。

我希望有所幫助!

我建議一些通常是代碼氣味的東西 - 默認的可變參數。

瑣碎的例子:

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

您的dict(或列表,或任何可變的)綁定到函數對象。 當省略cache關鍵字參數時,后續調用將引用同一對象。 此對象狀態將在調用之間保持不變。

我不喜歡外部范圍的var的想法,可能建議使用閉包,我認為這是更好的方式,因為你看它更像JavaScript,所以你可以使用函數作為對象:

def foo():
    const = 1
    def bar(param):
      return const + param
    return bar

a = foo()
print(a(5))

還有一個你沒有提到的替代方案,這是IMO最狡猾的方式,它不會創造一個扔掉的名字:)

def foo(variant):
    try:
        return foo.invariant + variant
    except AttributeError:
        foo.invariant = 1
        return foo(variant)

雖然堅持使用std庫是最好的。

我不認為你的兩個第一個例子是等價的。 第一個似乎是閉包,而第二個使用全局常量。 無論如何,對於第一個例子,python中的直接等價物將是

def f(x):
   def g(y):
      return x + y
   return g

並使用它

add2 = f(2)
print(add2(3)) # == 5

實際上,你的實現使用partial ,在引擎蓋下做了類似的事情

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM