str.startswitch使用高阶函数



我有一个文件,我想从中清除注释行我想使用functools.partial进行操作,类似于以下方式:

from functools import partial
f = open(filetoread, "r")
lines = f.readlines()
f.close()
# Filtering the comment lines
f_func = partial(str.startswith, prefix="#")
lines = filter(f_func, lines)

这不起作用,显然是因为str.startswith是一个类方法。functools.partialstr.startswith配合使用的正确方法是什么?

您有三个问题:

首先,str.startswith不接受关键字参数,它只接受位置参数。它是用C语言实现的,并使用PyArg_ParseTuple来获取它的位置参数。没有什么可以告诉Python它们有什么名称,因为名称prefix只出现在文档字符串中。所以prefix=是不好的。问题与此类似:

>>> str.startswith('#hi', prefix='#')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: startswith() takes no keyword arguments
>>> def foo(self,prefix,start=None,end=None): return str.startswith(self,prefix,start,end)
...
>>> foo('#hi', prefix='#')
True

其次,str.startswith的第一个参数不是前缀,而是self,我们要检查它是否有前缀的对象。作为一个方法,它没有固有的问题,如果有一个名为str.isprefixof的方法,或者这个方法是在Python中实现的,你就可以了。但事实并非如此。

最后,functools.partial只允许您绑定初始位置参数,它不知道如何绑定第二个,但不知道第一个。由于要绑定的参数不是第一个,而且无法通过名称访问,因此您没有选择。

不过,对于这种情况,有一种变通方法可以编写函数式代码。你只需要operator.methodcaller,而不是functools.partial:

f_func = operator.methodcaller('startswith', '#')

operator.methodcaller绑定除第一个参数之外的所有参数


既然你问使用functools的正确方法是什么,我想你可以用一个额外的高阶函数来反转参数:

def flip(func):
    return lambda x,y: func(y,x)
f_func = partial(flip(str.startswith), '#')

你可能会认为这是"作弊",因为它使用了lambda,如果我们想使用lambda,我们会像Daniel的回答一样使用它。但我们使用它来实现Python没有提供的一个基本的高阶函数,一旦解决了这个问题,定义f_func就感觉很好,很实用。

请注意,我并没有实现这个高阶函数,特别是在Python术语中的,因为我不像partial那样提供任何元数据。它具有func只读属性,用户可能会合理地希望flip也提供该属性。

或者,您可以像上面的foo一样,为str.startswith编写一个Python包装器,并将partial应用于它。

我不认为partial是正确的工具。相反,您可以使用lambda:

func = lambda s: s.startswith('#')
lines = filter(func, lines)

尽管需要注意的是,Python并不是一种真正的函数式语言,而且实现这一点的一种更Python的方式是列表理解:

lines = [line for line in lines if line.startswith('#')]

相关内容

  • 没有找到相关文章

最新更新