Python map函数,通过引用/值传递?

时间:2011-08-26 10:23:11

标签: python

我对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

3 个答案:

答案 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
  • 引用是一个变量 stricto sensu ,也就是说“一大块” 内容可以更改的内存“。引用的值是对象的地址。
  • 对象有一个 基于语言C的结构的实现 Python的基础。

其他词也用于指定'标识符':
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

     

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

答案 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之外工作时却不需要?