たとえば、python組み込みのpow()
関数を例にとります。
xs = [1,2,3,4,5,6,7,8]
from functools import partial
list(map(partial(pow,2),xs))
>>> [2, 4, 8, 16, 32, 128, 256]
しかし、どうすればxsを2の累乗に上げることができますか?
取得するため [1, 4, 9, 16, 25, 49, 64]
list(map(partial(pow,y=2),xs))
TypeError: pow() takes no keyword arguments
リスト内包表記の方が簡単でしょう。
私はこの単純なワンライナーを使用すると思います:
_import itertools
print list(itertools.imap(pow, [1, 2, 3], itertools.repeat(2)))
_
更新:
また、便利な解決策よりもおかしな方法を考え出しました。 Python3では、_...
_リテラルがEllipsis
を意味するという事実から、これは美しい構文上の砂糖です。これはpartial
の変更バージョンであり、左端と右端の間の位置引数の一部を省略できます。唯一の欠点は、Ellipsisを引数として渡すことができないことです。
_import itertools
def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*(newfunc.leftmost_args + fargs + newfunc.rightmost_args), **newkeywords)
newfunc.func = func
args = iter(args)
newfunc.leftmost_args = Tuple(itertools.takewhile(lambda v: v != Ellipsis, args))
newfunc.rightmost_args = Tuple(args)
newfunc.keywords = keywords
return newfunc
>>> print partial(pow, ..., 2, 3)(5) # (5^2)%3
1
>>> print partial(pow, 2, ..., 3)(5) # (2^5)%3
2
>>> print partial(pow, 2, 3, ...)(5) # (2^3)%5
3
>>> print partial(pow, 2, 3)(5) # (2^3)%5
3
_
したがって、元の質問の解決策は、このバージョンのパーシャルlist(map(partial(pow, ..., 2),xs))
を使用することです。
なぜ引数とその部分を並べ替える簡単なラムダ関数を作成しないのですか?
partial(lambda p, x: pow(x, p), 2)
このためのヘルパー関数を作成できます。
from functools import wraps
def foo(a, b, c, d, e):
print('foo(a={}, b={}, c={}, d={}, e={})'.format(a, b, c, d, e))
def partial_at(func, index, value):
@wraps(func)
def result(*rest, **kwargs):
args = []
args.extend(rest[:index])
args.append(value)
args.extend(rest[index:])
return func(*args, **kwargs)
return result
if __name__ == '__main__':
bar = partial_at(foo, 2, 'C')
bar('A', 'B', 'D', 'E')
# Prints: foo(a=A, b=B, c=C, d=D, e=E)
免責事項:私はこれをキーワード引数でテストしていないため、どういうわけかそれらのために爆発するかもしれません。また、これが@wraps
の使用目的であるかどうかはわかりませんが、それは正しいようです。
あなたはクロージャーを使うことができます
xs = [1,2,3,4,5,6,7,8]
def closure(method, param):
def t(x):
return method(x, param)
return t
f = closure(pow, 2)
f(10)
f = closure(pow, 3)
f(10)
それを行う1つの方法は次のとおりです。
def testfunc1(xs):
from functools import partial
def mypow(x,y): return x ** y
return list(map(partial(mypow,y=2),xs))
ただし、これには、pow関数の再定義が含まれます。
パーシャルの使用が「必要」でない場合、単純なラムダがうまくいきます
def testfunc2(xs):
return list(map(lambda x: pow(x,2), xs))
そして、2の捕虜をマップする特定の方法は、
def testfunc5(xs):
from operator import mul
return list(map(mul,xs,xs))
しかし、これらはいずれも、キーワード引数に関連する部分的な適用の問題に直接対処するものではありません。
これは、functools.partial()
よりも柔軟なlambda
を使用して行うことができます。
pow_two = lambda base: pow(base, 2)
print(pow_two(3)) # 9
より一般的には:
def bind_skip_first(func, *args, **kwargs):
return lambda first: func(first, *args, **kwargs)
pow_two = bind_skip_first(pow, 2)
print(pow_two(3)) # 9
ラムダの欠点の1つは、一部のライブラリがシリアル化できないことです。
非常に用途の広い funcy には、この問題に正確に対処するrpartial
関数が含まれています。
xs = [1,2,3,4,5,6,7,8]
from funcy import rpartial
list(map(rpartial(pow, 2), xs))
# [1, 4, 9, 16, 25, 36, 49, 64]
それはただのラムダです:
def rpartial(func, *args):
"""Partially applies last arguments."""
return lambda *a: func(*(a + args))
ラムダ関数を使用できない場合は、引数を並べ替える単純なラッパー関数を作成することもできます。
def _pow(y, x):
return pow(x, y)
そして次に電話する
list(map(partial(_pow,2),xs))
>>> [1, 4, 9, 16, 25, 36, 49, 64]
すでに述べたように、これは functools.partial
partial
にする関数がキーワード引数を受け入れない場合。
外部ライブラリを使用してもかまわない場合 1iteration_utilities.partial
プレースホルダーをサポートするパーシャルがあります:
>>> from iteration_utilities import partial
>>> square = partial(pow, partial._, 2) # the partial._ attribute represents a placeholder
>>> list(map(square, xs))
[1, 4, 9, 16, 25, 36, 49, 64]
1 免責事項:私は iteration_utilities
ライブラリ(インストール手順は ドキュメントにあります 興味がある場合に参照できます)。