地图与列表;为什么不同的行为?

时间:2016-04-05 05:33:01

标签: python python-3.x functional-programming

在实施"变量消除"贝叶斯的算法'网络程序,我遇到了一个意外的错误,这是一系列对象的迭代映射转换的结果。

为简单起见,我在这里使用类似的代码:

>>> nums = [1, 2, 3]
>>> for x in [4, 5, 6]:
...     # Uses n if x is odd, uses (n + 10) if x is even
...     nums = map(
...         lambda n: n if x % 2 else n + 10, 
...         nums)
...
>>> list(nums)
[31, 32, 33]

这绝对是错误的结果。由于[4,5,6]包含两个偶数,因此应将10添加到每个元素最多两次。我在VE算法中也遇到了意想不到的行为,所以我修改它以在每次迭代后将map迭代器转换为list

>>> nums = [1, 2, 3]
>>> for x in [4, 5, 6]:
...     # Uses n if x is odd, uses (n + 10) if x is even
...     nums = map(
...         lambda n: n if x % 2 else n + 10,
...         nums)
...     nums = list(nums)
...
>>> list(nums)
[21, 22, 23]

根据我对可迭代的理解,这个修改不应该改变任何东西,但确实如此。显然,n + 10案例的not x % 2转换在list版本中应用次数较少。

My Bayes Nets程序在发现此错误后也能正常工作,但我正在寻找解释原因的原因。

3 个答案:

答案 0 :(得分:12)

答案非常简单:{3}}是Python 3中的map函数,它返回一个可迭代对象(在Python 2中它返回list)。让我为你的例子添加一些输出:

In [6]: nums = [1, 2, 3]

In [7]: for x in [4, 5, 6]:
   ...:     nums = map(lambda n: n if x % 2 else n + 10, nums)
   ...:     print(x)
   ...:     print(nums)
   ...:     
4
<map object at 0x7ff5e5da6320>
5
<map object at 0x7ff5e5da63c8>
6
<map object at 0x7ff5e5da6400>

In [8]: print(x)
6

In [9]: list(nums)
Out[9]: [31, 32, 33]

注意In[8] - x的值为6.我们还可以转换lambda函数,传递给map以跟踪{{1}的值1}}:

x

因为In [10]: nums = [1, 2, 3] In [11]: for x in [4, 5, 6]: ....: nums = map(lambda n: print(x) or (n if x % 2 else n + 10), nums) ....: In [12]: list(nums) 6 6 6 6 6 6 6 6 6 Out[12]: [31, 32, 33] 是惰性的,它会评估何时调用map。但是,list的值为x,这就是产生混乱输出的原因。评估循环内的6会产生预期的输出。

nums

答案 1 :(得分:5)

问题与您正在创建的lambda函数如何访问x变量有关。 Python的作用域的工作方式,lambda函数在被调用时将始终使用来自外部作用域的最新版x,而不是它们被定义时的值。

由于map是惰性的,因此直到循环之后才会调用lambda函数(当你通过将嵌套map传递给list时使用嵌套x)时,它们会被调用全部使用最后x值。

要使每个lambda函数保存x=x定义的值,请像这样添加lambda n, x=x: n if x % 2 else n + 10

x

指定参数及其默认值。默认值将在定义lambda时进行计算,因此当稍后调用lambda(没有第二个参数)时,表达式中的 $query = "SELECT pass FROM social WHERE id = 11"; // took the (``) out of the query and added this im assuming the value is stored in the $row variable and I may be able to use $row with the user input to verify hash via bcrypt!!! $result = $conn->query($query); while($row = mysqli_fetch_array($result)) { echo $row['pass']; echo "<br />"; } 将是保存的默认值。

答案 2 :(得分:3)

如果您想使用延迟版本,则需要在每个循环中修复xfunctools.partial正是这样做的:

from functools import partial

def myfilter(n, x):
    return n if x % 2 else n + 10

nums = [1, 2, 3]
for x in [4, 5, 6]:
    f = partial(myfilter, x=x)
    nums = map(f, nums)

>>> list(nums)
[21, 22, 23]