5

假设您想定义一个以任意顺序设置位置参数的部分,即您想将部分应用到str.split以固定第二个和第三个参数。所需的结果与以下内容相同:

lambda s: str.rsplit(s, SEP, 1) # SEP given.

(我使用str.rsplit(s...而不是s.rsplit(...使这一点更清楚)。

使用functools.partial的一些近似值是:

partial(str.rsplit, sep=SEP, maxsplit=1) # SEP given

但是str.rsplit不使用关键字参数,只使用位置参数。

如何部分解决这些论点?lamda 和 wrappers 是唯一的选择吗?

如果您想内联定义函数,包装器很丑陋,例如为函数的参数定义它。Lambda是这里的事实,部分另一种选择,但在这种情况下似乎缺乏。

4

2 回答 2

6

你不能用partial. 这是因为split使用了PyArg_ParseTupleC API 中不提供关键字参数的函数。从 python 的角度来看,如果方法被定义为:

def split(self, *args):
    if len(args) > 2:
        raise TypeError(...)
    sep = args[0] if args else None
    maxsplit = args[1] if len(args) > 1 else -1
    ...

Partial 只能按顺序分配位置参数。这在文档中提到,他们在其中声明partial“大致相当于”:

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

请注意,return func(*(args + fargs), **newkeywords)这清楚地表明您传递给的参数partial被附加到其他函数参数。

结论是lambda比 更强大partial

附带说明一下,在 python3.3 中,您可以指定maxsplit为关键字参数:

>>> 'some string with spaces'.split(maxsplit=2)
['some', 'string', 'with spaces']

许多其他具有相同问题的方法/功能也是如此。

于 2013-03-26T18:57:33.437 回答
5

因为str.rsplit你真的想operator.methodcaller()改用:

>>> from operator import methodcaller
>>> SEP = ' '
>>> s = methodcaller('rsplit', SEP, 1)
>>> s('Test one two')
['Test one', 'two']
于 2013-03-26T18:26:53.863 回答