我对Python中的map
函数有疑问。
根据我的理解,该函数不会改变它正在运行的列表,而是创建一个新的并返回它。这是对的吗?
此外,我还有以下代码
def reflect(p,dir):
if(dir == 'X'):
func = lambda (a,b) : (a * -1, b)
else:
func = lambda (a,b) : (a, b * -1)
p = map(func,p)
print 'got', p
points
是一个元组数组,例如:[(1, 1), (-1, 1), (-1, -1), (1, -1)]
如果我以这种方式调用上述功能:
print points
reflect(points,'X')
print points
列表points
不会改变。在函数内部,打印功能正确打印出我想要的内容。
有人可能会指点我某个方向,我可以在python中了解所有这些通过值/参考等的方法,以及我如何解决上述问题?或者也许我在努力模仿Hthon中的Haskell ......
由于
编辑:
说而不是p = map(func,p)
我做
for i in range(len(p)):
p[i] = func(p[i])
列表的值在函数外部更新,就像通过引用一样工作。呃,希望这很清楚:S
答案 0 :(得分:12)
您误解了引用在Python中的工作原理。这里,所有名称都是引用,没有“值”。名称绑定到对象。但是=
不会修改名称所指向的对象 - 它会将名称重新绑定到另一个对象:
x = 42
y = x
# now:
# 'is' is a identity operator — it checks whether two names point to the
# exact same object
print x is y # => True
print x, y # 42 42
y = 69
# now y has been rebound, but that does not change the '42' object, nor rebinds x
print x is y # => False
print x, y # 42 69
要修改对象本身,它需要是可变的 - 即暴露使其变异或具有可修改的dict的成员。重新绑定p
时会发生与上述相同的事情 - 它根本不会触及points
,它只是修改了本地p
名称的含义。
如果要模拟类似C ++的引用,则需要将对象封装到可变容器中,例如:一个清单。
reflect([points], 'X')
# inside reflect:
p[0] = ...
但是你不应该,至少在这种情况下 - 你应该只返回新对象。
points = reflect(points, 'X')
# inside reflect, instead of p = ...
return map(func, p)
好吧,既然我想到了,你也可以做到
p[:] = map(func, p)
但同样,返回新对象通常会更好。
答案 1 :(得分:0)
Python的数据模型基于三部曲:
标识符 - 引用 - 对象
string
。 其他词也用于指定'标识符':
1)姓名
2)变量;因为转喻在数学中使用这个词来表示代表真实数学变量的符号,并且计算机中的变量在概念上与数学变量具有相同的功能(它们的值可以改变)。
在我看来,这在Python中的使用是一个非常糟糕的习惯:它会在计算机科学中产生模糊性和混淆:“内容可以改变的”内存块“。
最好的方法是使用:identifier
标识符和对象绑定在某个名称空间中。命名空间以Python的字典形式显示,但它们不是字典。
标识符与对象的绑定是间接的,通过引用。
标识符和引用的绑定是直接的,并在SYMBOL TABLE(或符号表)中实现。
在计算机科学中,符号表是a使用的数据结构 语言翻译,如编译器或解释器,每个 程序源代码中的标识符与信息相关联 与其在来源中的声明或出现有关,例如其 类型,范围等级,有时还有其位置 http://en.wikipedia.org/wiki/Symbol_table
他们说:标识符。正是。
我很少看到符号表的暗示,尽管它是揭示Python数据模型IMO功能的关键因素。
在我看来,这个词
绑定
没有指定一个精确而独特的机制,而是全局涉及三部曲标识符的所有机制的集合 - 参考 - 对象
我不假装我完全理解有关Python的数据和执行模型的所有问题,并且上述考虑因素可以更准确,更精确地表达。
但是,它们使我能够对执行代码期间发生的情况有所了解
如果我错了,我会非常乐意在某些方面得到纠正(例如,我非常满意从Michael Foord那里学到名称空间的性质不是字典,这只是它们的代表方式)
那就是说,当我讨论在Python中传递某些东西作为参数的主题时,我不知道什么是所谓的价值和参考,而且我的印象是很多人在这个主题上表达了很多深奥的内容。讨论不仅仅比我更了解。 我认为Alex Martelli的这个主题没有最好的和清晰的意见:
“尝试重用更常用的术语 “变量是盒子”到“变量”的语言 是post-it标签“是,恕我直言,更容易混淆而不是帮助。”
Alex Martelli
答案 2 :(得分:0)
我想碰这个。答案并没有真正回答这个问题 - 他们忽视了OP能够通过迭代实现预期结果的事实。问题归结为map
的行为。这是一个更直接的例子:
f=(lambda pair: pair[0].append(pair[1]))
a = ([],1)
f(a)
print(a) #prints ([1],1)
a=([],1)
map(f,[a])
print(a) #prints ([0],1)
因此,map不会以OP期望的方式改变对象。我也有同样的困惑。
有人可以评论这里发生了什么吗?我认为这是OP问题的一个很好的答案。
请注意,如果我们按如下方式分配map
的输出,我们会有不同的行为(根据Cat Plus Plus'回答)
f=(lambda pair: pair[0].append(pair[1]))
a = ([],1)
x = [a]
x[:] = map(f,x)
print(x) #prints None
print(a) # prints [1]
请注意,在第一个示例中,我们只调用了f(a)
,而不是a=f(a)
。为什么我们在使用map
时需要分配,而在map
之外工作时却不需要?