2016-07-03 105 views
0

我使用從functools模塊的部分的方法的功能的範圍內的值的映射:functools.partial:類型錯誤:得到多個值關鍵字參數

def basic_rule(p,b,vx=1,**kwargs): 
    return (p/b) if vx != 0 else 0 

def rule5(func,**kwargs): 
    vals = map(functools.partial(func,**kwargs), range(1,kwargs['b']+1)) 
    return [x for i,x in enumerate(vals[:-1]) if x >= vals[i+1]] == [] 

rule5(basic_rule,p=100,b=10000) 

這裏是我得到線錯誤5:

----> return map(functools.partial(func,**kwargs), range(1,kwargs['b']+1)) 

TypeError: basic_rule() got multiple values for keyword argument 'p' 

看起來functools.partial試圖分配範圍的參數p,即使我已經賦值給它。我試圖將範圍分配給vx的值。任何想法我可以做到這一點?

編輯:添加了一點額外的上下文的代碼。基本上我想測試5做的是確保給它的函數的結果隨着vt的增加而增加,以便`func(vt = 1)< func(vt = 2)... < func(vt = N)。

+0

basic_rule中** kwargs的用途是什麼? –

+0

爲什麼使用'functools.partial()'而不是lambda? –

+1

如果vx!= 0 else 0'變爲'kwargs [「p」]/kwargs [「b」]並且'basic_rule(vx = 1,** kwargs):'的函數簽名會避免錯誤但不確定你的最終目標是什麼 –

回答

0

functools.partial生成部分,其存儲參數receiveids在2個屬性:

  • arguments存儲位置參數
  • keywords存儲的所有關鍵字參數

所以部分可以調用原始函數完全按照預期進行。換句話說,當你調用生成的部分用一個參數(比如說,1)這將是一樣的:

original_func(1, **kwargs) 

當你的kwargs中包含的第一個參數 - 和你傳遞的「1」作爲一個位置參數 - 你會得到錯誤。

我不確定它是否會在這種特殊情況下工作,但一個解決方案可以使用inspect.getargspeckwargs中提取可作爲位置參數傳遞的參數。在這種情況下,rule5函數將類似於:

def rule5(func, **kwargs): 
    # let's save 'b' argument because we'll need it in the range call 
    b = kwargs['b'] 
    original_args = inspect.getargspec(func).args 
    # extract from kwargs all arguments that can be passed as positional 
    new_args = [kwargs.pop(key) for key in original_args if key in kwargs] 
    # construct the partial passing as much positional arguments as possible 
    fn = functools.partial(func, *new_args, **kwargs) 
    # now map will pass the range result as the next positional argument 
    vals = map(fn, range(1, b+1)) 
    return [x for i,x in enumerate(vals[:-1]) if x >= vals[i+1]] == [] 
相關問題