在python中将带有两个参数的函数传递给filter()

在python中将带有两个参数的函数传递给filter(),python,list,python-2.7,Python,List,Python 2.7,鉴于以下清单: DNA_list = ['ATAT', 'GTGTACGT', 'AAAAGGTT'] 我想筛选长度超过3个字符的字符串。我通过以下代码实现这一点: 对于for循环: long_dna = [] for element in DNA_list: length = len(element) if int(length) > 3: long_dna.append(element) print long_dna def get_long(dna

鉴于以下清单:

DNA_list = ['ATAT', 'GTGTACGT', 'AAAAGGTT']
我想筛选长度超过3个字符的字符串。我通过以下代码实现这一点:

对于for循环:

long_dna = []
for element in DNA_list:
    length = len(element)
    if int(length) > 3:
        long_dna.append(element)
print long_dna
def get_long(dna_seq, threshold):
    return len(dna_seq) > threshold

long_dna_loop2 = []
for element in DNA_list:
    if get_long(element, 3) is True:
        long_dna_loop2.append(element)
print long_dna_loop2
但我希望我的代码更加通用,以便以后可以过滤任意长度的字符串,因此我使用函数和for循环:

long_dna = []
for element in DNA_list:
    length = len(element)
    if int(length) > 3:
        long_dna.append(element)
print long_dna
def get_long(dna_seq, threshold):
    return len(dna_seq) > threshold

long_dna_loop2 = []
for element in DNA_list:
    if get_long(element, 3) is True:
        long_dna_loop2.append(element)
print long_dna_loop2
我想使用
filter()
实现同样的通用性,但我无法实现这一点。如果我使用上述函数
get_long()
,当我将其与
filter()
一起使用时,我就无法向其传递参数。这是不可能的,还是有办法解决

针对特定情况,使用
filter()
的我的代码:

def is_long(dna):
        return len(dna) > 3

    long_dna_filter = filter(is_long, DNA_list)

使用
lambda
提供阈值,如下所示:

filter(lambda seq: get_long(seq, 3),
       dna_list)

您可以使
is_long
返回一个函数,该函数可以接受
dna
,如下所示

>>> def is_long(length):
...     return lambda dna: len(dna) > length
... 
>>> filter(is_long(3), DNA_list)
['ATAT', 'GTGTACGT', 'AAAAGGTT']
>>> filter(is_long(4), DNA_list)
['GTGTACGT', 'AAAAGGTT']
if get_long(element, 3):
    long_dna_loop2.append(element)
然后在
过滤器中使用它,如下所示

>>> def is_long(length):
...     return lambda dna: len(dna) > length
... 
>>> filter(is_long(3), DNA_list)
['ATAT', 'GTGTACGT', 'AAAAGGTT']
>>> filter(is_long(4), DNA_list)
['GTGTACGT', 'AAAAGGTT']
if get_long(element, 3):
    long_dna_loop2.append(element)

注意:不要使用
is
运算符来比较布尔值或数字。相反,要尽可能依赖数据的真实性。所以,在你的情况下,你可以这样写你的第二个版本

>>> def is_long(length):
...     return lambda dna: len(dna) > length
... 
>>> filter(is_long(3), DNA_list)
['ATAT', 'GTGTACGT', 'AAAAGGTT']
>>> filter(is_long(4), DNA_list)
['GTGTACGT', 'AAAAGGTT']
if get_long(element, 3):
    long_dna_loop2.append(element)
引用

不要使用==将布尔值与True或False进行比较

 Yes:   if greeting:
 No:    if greeting == True:
 Worse: if greeting is True:

您试图做的是:您有一个具有多个参数的函数(在本例中为2),并且希望从该函数派生一个具有一个或多个固定参数的函数,然后可以将其传递到
过滤器

有些语言(特别是函数式语言)具有“内置”此功能。在python中,您可以使用lambdas来实现这一点(如其他人所示),也可以使用。特别是:

partial()用于partial函数应用程序,它“冻结”函数参数和/或关键字的某些部分,从而生成具有简化签名的新对象。例如,partial()可用于创建一个可调用函数,其行为类似于int()函数,其中基参数默认为两个:

>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.'
>>> basetwo('10010')
18
因此,您可以:

filter(functools.partial(get_long, treshold=13), DNA_list)

是否需要使用
过滤器()
?为什么不使用一个更具python风格的列表理解呢

例如:

>>> DNA_list = ['ATAT', 'GTGTACGT', 'AAAAGGTT']
>>> threshold = 3
>>> long_dna = [dna_seq for dna_seq in DNA_list if len(dna_seq) > threshold]
>>> long_dna
['ATAT', 'GTGTACGT', 'AAAAGGTT']

>>> threshold = 4
>>> [dna_seq for dna_seq in DNA_list if len(dna_seq) > threshold]
['GTGTACGT', 'AAAAGGTT']
这种方法的优点是,将其转换为生成器非常简单,生成器可以根据您的应用程序提供更好的内存和执行,例如,如果您有很多DNA序列,并且希望对它们进行迭代,将它们实现为列表将一次性消耗大量内存。等效生成器只需将方括号
[]
替换为圆括号
()

>>long_dna=(如果len(dna_seq)>阈值,则dna_seq代表dna_seq在dna_列表中)
>>>列表(长)
['GTGTACGT','AAAAGGTT']

在Python2中,
filter()
不能选择这种性能改进,因为它返回一个列表。在Python 3中,
filter()
返回更类似于生成器的筛选器对象。

以下是使用
lambda
的更多方法。第一个使用默认关键字参数来保存所需的长度。第二个简单地将所需的长度嵌入
lambda
主体中

#Create a list of strings
s = 'abcdefghi'
data = [s[:i+1] for i in range(len(s))]
print data

thresh = 3
print filter(lambda seq, n=thresh: len(seq) > n, data)

print filter(lambda seq: len(seq) > 5, data)
输出

['a', 'ab', 'abc', 'abcd', 'abcde', 'abcdef', 'abcdefg', 'abcdefgh', 'abcdefghi']
['abcd', 'abcde', 'abcdef', 'abcdefg', 'abcdefgh', 'abcdefghi']
['abcdef', 'abcdefg', 'abcdefgh', 'abcdefghi']
在第一个示例中,您还可以执行以下操作:

print filter(lambda seq, n=3: len(seq) > n, data)
类似地,在第二个示例中,可以用局部(或全局)变量替换literal
5
,例如:

thresh = 5
print filter(lambda seq: len(seq) > thresh, data)

您始终可以创建一个callable,该callable返回一个适合于
filter
进行比较的callable,如下例所示:

def main():
    dna_list = ['A', 'CA', 'TGATGATAC', 'GGGTAAAATC', 'TCG', 'AGGTCGCT', 'TT',
                'GGGTTGGA', 'C', 'TTGGAGGG']
    print('\n'.join(filter(length_at_least(3), dna_list)))


def length_at_least(value):
    return lambda item: len(item) >= value

# length_at_least = lambda value: lambda item: len(item) >= value

if __name__ == '__main__':
    main()

你可以有一个更一般的情况

由于函数是python中的一个对象,因此可以创建另一个函数,返回所需的函数。

def f(threshhold):
    def g(x):
        return len(x)>threshhold
    return g #return a function

this_function = f(3)

DNA_list = ['ATAT', 'GTGTACGT', 'AAAAGGTT','AAA','AAAA']
filter(this_function, DNA_list)

output: ['ATAT', 'GTGTACGT', 'AAAAGGTT', 'AAAA']

g是您真正想要的,f是创建它的函数。

我使用了不同的解决方案,使用了内部函数和非局部作用域,如下所示。我已经修改了这个原始代码以便于理解,因为我的代码是不同的

希望这有帮助。:)


就我个人而言,无论如何,我发现列表理解比
filter
应用程序更容易阅读。