我需要做一个lambda表达式,从一个有多个参数的列表返回函数的名称,我写了下面的代码,但不是给我函数的名称,它返回这个<函数funB在0x01FDBE80>我该怎么修理它?函数funB在0x01FDBE80>
def funA():
pass
def funB(a):
pass
def funC(a, b):
pass
n = [funA, funB, funC]
m = list(filter(lambda x: x.__name__ if x.__code__.co_argcount > 0 else None, n))
print(m)
问题是filter
使用函数,它是作为一个布尔谓词纯粹用于过滤,而不是用于改变产生值。
在本例中,它将把x.__name__ if x.__code__.co_argcount > 0 else None
为True
的所有函数添加到生成的生成器中,但它将按原样添加函数对象本身,而不是其.__name__
属性。
From the docs:
从iterable中返回true的元素构造一个迭代器。Iterable可以是序列、支持迭代的容器或迭代器。如果function为None,则假定为恒等函数,即删除iterable中所有为false的元素。注意,如果function不为None, filter(function, iterable)等价于生成器表达式(item for item in iterable,如果function(item));如果function为None,则等价于(item for item in iterable,如果item)。
这就是为什么
m = list(filter(lambda x: x.__code__.co_argcount > 0, n))
将给出与当前代码相同的输出。
在这种情况下你不应该使用filter
:
m = list(f.__name__ for f in n if f.__code__.co_argcount > 0)
为了避免这样的副作用,只需添加进一步的步骤(参见DeepSpace的解释),使用map
过滤并检索名称(根据需要)。
fs = [funA, funB, funC]
fs_filtered = map(lambda f: f.__name__, filter(lambda f: f if f.__code__.co_argcount > 0 else None , fs))
print(list(fs_filtered))
或更好:
fs_filtered = filter(None, map(lambda f: f.__name__ if f.__code__.co_argcount > 0 else None, fs))
print(list(fs_filtered ))
Appendum:filter
仅用于过滤器,不支持对迭代器项的操作。在这个例子中,print
工作得很好,但是.__name__
在
m = list(filter(lambda f: (print(f.__name__), f.__name__)[1] if f.__code__.co_argcount > 0 else None, fs))
# funB
# funC
# [<function funB at 0x7f6337eeddc0>, <function funC at 0x7f6337eede50>]