代码
def change1(list1):
list1[1] = list1[1] + 5
def change2(number):
number = number + 2
def main():
numbers = [4, 8, 12]
change1(numbers)
variable = 15
change2(variable)
i = 0
while i < 3:
print numbers[i]
i += 1
print variable
main()
当我阅读它时,我认为它会输出4 8 12 15
,但会输出4 13 12 15
。我在这里可以看到Python处理整数和列表的方式不同,我认为没有全局,最后一件事是不可能的。我无法理解输出,在这种情况下,为什么不输出4 13 12 17
?
你可以在这里看到几乎相同的代码,它们有不同的类型和不同的参考:
$ python test2.py
4
13
12
15
$ python test3.py
4
13
12
17
$ cat test2.py test3.py
传递参考示例
test2.py:传递引用和可变数据类型-example。表/列表不足以影响main中的局部变量,需要Reference!
def change1(list1):
list1[1] = list1[1] + 5
def change2(number):
number = [x+2 for x in number]
def main():
numbers = [4, 8, 12]
change1(numbers)
variable = [15]
change2(variable)
i = 0
while i < 3:
print numbers[i]
i += 1
print variable[0]
main()
test3.py:pass-by-reference示例,在主函数外部更改可变数据类型列表/表
def change1(list1):
list1[1] = list1[1] + 5
def change2(number):
number[0] += 2
def main():
numbers = [4, 8, 12]
change1(numbers)
variable = [15]
change2(variable)
i = 0
while i < 3:
print numbers[i]
i += 1
print variable[0]
main()
传值示例
test4.py:试图找到一个带值传递的例子,为什么它不起作用?
$ cat test4.py
# Not yet a pass-by-value example!
global variable
variable = [15]
def change1(list1):
list1[1] = list1[1] + 5
def change2(number):
number = [x+2 for x in number]
def main():
numbers = [4, 8, 12]
change1(numbers)
#variable = 15
change2(variable)
i = 0
while i < 3:
print numbers[i]
i += 1
print variable[0]
main()
$ python test4.py
4
13
12
15 # I expected 17! Why no 17?
答案 0 :(得分:2)
def change1(list1):
# `list1[1] =` means you are changing the object passed in
list1[1] = list1[1] + 5
def change2(number):
# `number = ` means you create a **new local variable**, number,
# based on the `number`you passed in
number = [x+2 for x in number]
因此,如果您想要更改现有对象,则必须以某种方式引用它们,例如在
中def change3(number):
# `number[:]` is the whole existing list and you overwrite it
number[:] = [x+2 for x in number]
更改列表时请注意[ .. ]
。
答案 1 :(得分:1)
Python参数通过引用传递。你只改变change1
中的一个对象。
但是,数值和字符串都是不可变的。您无法更改传入的不可变值,并在调用者中看到该值更改。另一方面,字典和列表是可变的,当函数返回时,被调用函数对它们所做的更改将被保留。
答案 2 :(得分:1)
确切的答案是Python实际上是“通过共享调用”,也称为“按对象调用”或“按对象引用调用”。
这是extensively discussed before。从那篇文章:
人们不时会在comp.lang.python上弹出那些读过一点CS而不是很多CS(或者只是一种CS)的人,并浪费了很多精力来告诉大家Python使用的是一些它并没有真正使用的调用模型。事实证明,他们并不真正理解Python的模型,而且他们常常也不了解他们最喜欢的模型。
但是没关系,你需要知道的唯一事情是Python的模型既不是“按值调用”也不是“按引用调用”(因为任何尝试将这些术语用于Python都要求你使用非标准的定义单词“-value”和“-reference”)。最准确的描述是CLU的“按对象调用”或“通过共享调用”。或者,如果您愿意,“按对象引用调用”。
如果您还没有这样做,也应该阅读this。
Python的语义最类似于语言CLU的语义。 Liskov 等的CLU参考手册描述了这样的语义:
“我们通过共享调用传递技术调用的参数, 因为参数对象是在。之间共享的 调用者和被调用的例程。这种技术没有 对应于大多数传统的论证传递技术 (它类似于在LISP中传递的论点)。 特别是它 不是按值调用因为参数的突变 由被调用的例程形成的调用者将可以看到。 并且不是按引用进行调用,因为没有给出访问权限 调用者的变量,但仅限于某些对象。“
答案 3 :(得分:0)
在change1
中,您可以使用value + 5
兑换列表中的值
在change2
中,您向number
添加了5。结果是一个新对象,不仅仅应用于传递的变量。
如果你来自C ++:不,Python中没有int& var
。
执行此操作时,您会得到预期的结果:
def change2(number):
return number + 5
variable = 15
variable = change2(variable)
如果您仍然不想返回值,则可以创建MutableInt
类。
class MutableInt(object):
def __init__(self, value = 0):
self._value = int(value)
def __add__(self, other):
self._value += int(other)
return self
def __sub__(self, other):
self._value -= int(other)
return self
...
答案 4 :(得分:0)
所有示例都显示按值调用。 Python只有call-by-value。没有按引用的方式调用。 python中的所有值都是引用(不可能有“对象”作为值)。因此,它是传递给函数时复制的引用。列表是可变的,因此可以通过共享引用来改变其内容。在change2中,您将重新分配一个局部变量以指向另一个对象,该对象与所有对局部变量的赋值一样,对任何调用范围都没有影响,因为它是按值调用的。