2011-10-18 65 views
25

基本上,我想要做的是:如何用python部分填充特定的位置參數?

>>> from functools import partial 
>>> partial(str.startswith, prefix='a')('a') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: startswith() takes no keyword arguments 

但更普遍的問題是,如何填寫具體位置參數與partial

P.S.我意識到我可以使用lambda代替。

+1

繼續使用'lambda'。它會稍微慢一些,因爲'partial'是在C中實現的。如果性能很高,你也可以在C中實現你的變體。 – wberry

回答

32

這是無法完成的。你必須做一個包裝功能。

表面上,你會使用關鍵字參數,因爲你試圖做 - 這就是他們的目的,對吧?不幸的是,正如你發現的那樣,python的標準庫函數do not take named parameters。因此,在目前實現partial的情況下不可能實現另一個運行干擾的功能。

根據PEP 309的接受情況,接受包含的內容是「一個部分()類型的構造函數綁定最左邊的位置參數和任何關鍵字。」此外,它指出:

注意,當對象被調用,就好像它是一個函數,位置參數是所附到提供給構造的那些,並且關鍵字參數重寫並增強那些提供給構造。

位置參數,關鍵字參數或兩者都可以在創建對象和調用它時提供。

由於額外的位置參數被所附,就沒有辦法提供一些前述位置參數(由此實現)。

然而,接着說:

部分應用的參數從,或插入參數在任意位置創建它自己的問題,而是一個良好的實施和非混淆語義未決發現,我不認爲應該排除。

所以,它顯然可以放在桌子上,但是就目前而言,它並沒有以這種方式實現。

爲了公開起見,上面引用的重點是我自己的。

0

使用此代碼:

# See: functoolspartial for binding... 

class Function(object): 
    def __init__(self, fn): 
     self.fn = fn 

    def __call__(self, *args, **kwargs): 
     return self.fn(*args, **kwargs) 

    def __add__(self, other): 
     def subfn(*args, **kwargs): 
      return self(*args, **kwargs) + other(*args, **kwargs) 
     return subfn 


class arg(object): 
    """Tagging class""" 
    def __init__(self, index): 
     self.index = index 


class bind(Function): 
    """Reorder positional arguments. 
    Eg: g = f('yp', _1, 17, _0, dp=23) 
    Then g('a', 'b', another=55) --> f('yp', 'b', 17, 'a', dp=23, another=55) 
    """ 

    def __init__(self, fn, *pargs, **pkwargs): 
     # Maximum index referred to by the user. 
     # Inputs to f above this index will be passed through 
     self.fn = fn 
     self.pargs = pargs 
     self.pkwargs = pkwargs 
     self.max_gindex = max(
      (x.index if isinstance(x, arg) else -1 for x in pargs), 
      default=-1) 

    def __call__(self, *gargs, **gkwargs): 
     fargs = \ 
      [gargs[x.index] if isinstance(x, arg) else x for x in self.pargs] + \ 
      list(gargs[self.max_gindex+1:]) 

     fkwargs = dict(self.pkwargs) 
     fkwargs.update(gkwargs) # Overwrite keys 
     return self.fn(*fargs, *fkwargs) 

然後嘗試一下這樣的:

def myfn(a,b,c): 
print(a,b,c) 

bind(myfn, arg(1), 17, arg(0))(19,14) 
3

如果你真的需要這個,你可以使用rpartialfuncy第三方庫。

它的代碼是在這裏:

def rpartial(func, *args): 
    return lambda *a: func(*(a + args)) 

所以,你的情況下,可以如下處理:

>>> startswith_a = rpartial(str.startswith, 'a') 
>>> startswith_a('abc') 
True 
>>> startswith_a('def') 
False