2011-08-26 31 views
6

我对Python中的map函数有个疑问。Python映射函数,通过引用/值传递?

据我所知,该功能不发生变异它是在操作列表,而是创建一个新的,并将其返回。它是否正确 ?

此外,我有以下一段代码

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不变。在函数内部,打印功能正确地打印我想要的东西。

可能有人可能指向我的一些方向在那里我可以学到这一切路过值/参考等如何蟒蛇工作,我怎么能解决上面?或者,也许我过于卖力模仿哈斯克尔在蟒蛇...

感谢

编辑:

说的,而不是p = map(func,p)

for i in range(len(p)): 
    p[i] = func(p[i]) 

列表的价值在函数之外更新,就像通过引用工作一样。唉,希望这是明确的:S

+0

你能否更清楚地解释一下你的问题是什么?对Haskel程序员的参考对于Haskel程序员不是很有帮助。 – Achim

+0

嘿。是的,对不起,可能只是忽略了haskell的评论。我只是感到惊讶,即使我做了'p = map(func,p)',列表p在函数之外没有改变。如果我用列表迭代替换'p = map(func,p)',它似乎可行。 – rafalio

+0

Python既不是通过值传递也不是通过引用,python是通过对象。 –

回答

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 

要修改的对象本身,它需要是可变的 - 即公开该变异它的成员或有一个可修改的字典。当你重新绑定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) 

但同样,返回新的对象通常是更好的。

+0

好的,这是有道理的。我很困惑,并认为'='运算符的工作方式与它的不同,谢谢。 – rafalio

0

的Python的数据模型是基于三部曲:
标识符 - 参考 - 对象

  • 标识符是用代码编写的string
  • 参考是可变狭义,即“其内容的 内存块可以改变”。 参考的值是该对象的地址。
  • 对象有一个 实现基于langage C的结构,即Python的基础 。

其它词语也用于指定 '识别符':
1)名称
2)变量;因为这个词在数学中被转喻使用来表示代表真实数学变量的符号,并且计算机中的变量在概念上与数学变量(它们的值可以改变)具有相同的功能。
在我看来,Python中的这种用法是一种非常不好的习惯:它会在计算机科学中造成含糊不清和混淆,即“内存可能发生变化的内存块”。

最好是使用这个词:标识符

标识符和对象绑定在某个名称空间中。命名空间以Python的字典形式显示,但它们不是字典。

  • 的标识符和结合对象是间接的,通过参考。

  • 标识符和参考的绑定是直接的,并且在符号表(或符号表)中实现。

在计算机科学中,符号表是由一个 语言翻译器使用的数据结构,诸如编译器或解释,其中每个 标识符在一个程序的源代码与信息 与相关联的其声明或外观,例如其类型,范围级别以及其位置。
http://en.wikipedia.org/wiki/Symbol_table

他们说:标识符。恰恰。
我很少看到符号表的暗示,尽管它是揭示Python数据模型IMO功能的关键。

在我看来,这个词

结合

不指定精确和独特的机制,但全球范围内的关于三部曲标识的所有机制 - 参考 - 对象

我并不假装我完全理解了有关Python的数据和执行模型的所有问题,并且上述考虑事项可以更加精确和精确地表达出来。
但是,它们让我对运行代码期间发生的事情有了一个可操作的理解。
如果我错了,我会很高兴在某些问题上得到纠正(例如,我非常满意从迈克尔福德那里了解到名称空间的性质不是字典,而只是它们被表示的方式)

这就是说,我不知道什么是所谓的价值和参考,当讨论在Python中传递某些参数的主题时,我的印象是许多人已经在这个主题上表达了很多深奥的讨论不知道比我多。 我认为有没有关于该问题最好的和清晰的看法,这其中亚历克斯·马尔泰利的:

“试图重新使用更普遍适用于 语言,其中术语‘变量盒子’的语言其中“变量 是后贴标签”,恕我直言,更容易混淆,而不是帮助。“

亚历克斯·马尔泰利

http://bytes.com/topic/python/answers/37219-value-reference

+0

为了响应您的版主标记,只有问题可以有标签。答案自动具有与他们回答的问题相同的标记(不显示)。 –

+0

@付蜥蜴谢谢。过了一段时间,我意识到了。你的答案很有趣,因为你说答案也被标记为与问题相同,尽管标签没有显示。这是我想知道的事情:当我们使用标签进行搜索时会发生什么?现在我知道标签是由于答案被标记而被考虑在内的。 – eyquem

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) 

在OP期待的方式,使地图没有突变的对象。我也有同样的困惑。

任何人都可以评论到底发生了什么吗?我认为这对OP的问题会是一个很好的答案。

请注意,我们有不同的行为,如果我们指定的map输出如下(按猫加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以外的时候不需要分配?