str.strip 功能失调吗

Is str.strip dysfunctionning

我有一个从字符串拆分操作构建的列表,我想将它输入到 map() 函数,然后从它们的尾随括号和空格中删除这些子字符串。 并从中重建一个列表。

teststring=" (A) / (B) "
result = list(map(str.strip, teststring.split("/"), " ()"))

但最后,我只奇怪地去除了子字符串,而 "all combinations are tested",如文档所述。

我知道另一种方法可用于列表理解:

result = [substr.strip(' ()' for substr in teststring.split("/")]  

有效..但我想知道为什么地图不能正常工作。

我在 python 3.6.4,Anaconda 4.4 在 windows64。

补充问题;以下 topic 给出了一些查找函数源代码的指针。但是我找不到 map 的代码(通常是内置函数的代码),所以我看不出它是否有错误...

map 带有 3 个参数的行为与您想象的不同。 map 的第三个参数是 而不是 作为第一个参数提供的函数的参数。它用作第二个可迭代对象。

来自docs

map(function, iterable, ...) Return an iterator that applies function to every item of iterable, yielding the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. With multiple iterables, the iterator stops when the shortest iterable is exhausted. For cases where the function inputs are already arranged into argument tuples, see itertools.starmap()

换句话说:

map(str.strip, teststring.split('/'), ' ()') 等同于

[substr.strip(' ()' for substr in teststring.split('/')]。它远等同于

[(substr_1.strip(), substr_2.strip()) for (substr_1, substr_2) in zip(teststring.split("/"), ' ()')]

看出区别了吗?

map 的工作方式与您的使用方式不同。当您执行 map(f, a, b) 时,它会产生 f(a[0], b[0]), f(a[1], b[1]), ...,而您使用它时会产生 f(a[0], b), f(a[1], b), ....

要解决此问题,您可以使用问题中的列表推导式,或像 lambda string: string.strip(" ()").

这样的 lambda

问题是您似乎认为 map 的最后一个参数作为参数传递给了被映射的函数,但文档中并没有发生这种情况:

map(func, *iterables) --> map object

Make an iterator that computes the function using arguments from each of the iterables. Stops when the shortest iterable is exhausted.

换句话说,list(map(f, [1,2,3], 'abc')) 等同于:

[f(1,'a'), f(2, 'b'), f(3, 'c')]

这不是你想要的。你想 部分应用 string.strip 使用 " ()" 作为第二个参数,但是 " ()" 被当作另一个 iterable参数。所以,直接的解决方案,使用辅助函数:

In [9]: def strip_stuff(s):
   ...:     return s.strip(" ()")
   ...:

In [10]: list(map(strip_stuff, teststring.split("/")))
Out[10]: ['A', 'B']

如果你需要灵活,你可以做一个因子函数:

In [12]: def make_strip(stuff):
    ...:     def strip(s):
    ...:         return s.strip(stuff)
    ...:     return strip
    ...:

In [13]: list(map(make_strip(" ()"), teststring.split("/")))
Out[13]: ['A', 'B']

In [14]: list(map(make_strip("()"), teststring.split("/")))
Out[14]: [' (A) ', ' (B) ']

In [15]: list(map(make_strip(" )"), teststring.split("/")))
Out[15]: ['(A', '(B']

In [16]: list(map(make_strip(" ("), teststring.split("/")))
Out[16]: ['A)', 'B)']

你可以使用 operator.methodcaller:

list(map(operator.methodcaller('strip',' ()'),teststring.split("/")))

使用lambda函数可以实现如下:

map(lambda s: s.strip(" ()"), teststring.split("/"))