【问题标题】:Arguments are passed by reference or not in Python [duplicate]参数在Python中是否通过引用传递[重复]
【发布时间】:2014-03-08 02:15:08
【问题描述】:

Python 是通过引用还是通过值将参数传递给函数? 听说int和chars是按值传递的,而list和strings是按引用传递的。

但是当我写的时候-

def prepend(element,list):
    list = [element] + list

tryList = [1,2,3]
prepend(0,tryList)
print (tryList)

预期的输出是(假设列表是通过引用传递的)是: [0,1,2,3]。 但是实际输出的是:[1,2,3],说明是传值。

主要的困惑是在我写作时出现的

def appendList(element,l):
    l.append(element)
tryList = [1,2,3]
appendList(0,l)
print (l)

输出为:[1,2,3,0]

【问题讨论】:

  • 所有对象都是通过引用传递的,但是你重新绑定了列表。
  • 我怀疑实际输出是SyntaxError,因为try 是保留关键字。
  • @MartijnPieters:“对象”在 Python 中没有“通过”,因为“对象”不是值。 Python 中的所有值都是指向对象的指针。
  • @newacct:这完全取决于您定义的值;我将对象定义为值。名称都只是参考。
  • @MartijnPieters:你可以对 Java 说同样的话,但 Java 社区不会同意你的看法。 Python和Java的赋值和传递语义完全一样。

标签: python list arguments pass-by-reference


【解决方案1】:

list = [element] + list 创建一个新列表并覆盖原来的值,嗯,list。我没有将 element 添加到现有列表中,因此它不会演示通过引用传递。相当于:

list2 = [element] + list
list = list2

以下演示通过添加到现有列表而不是创建新列表来传递引用。

def prepend(element, _list):
    _list.insert(0, element)

_try = [1,2,3]
prepend(0, _try)
print(_try)

更新

如果我添加显示变量在程序执行时如何变化的打印语句,可能会更清楚。 prepend 有两种版本,一种用于创建新对象,另一种用于更新现有对象。 id() 函数返回对象的唯一标识符(在 cpython 中为对象的内存地址)。

def prepend_1(element, _list):
    print 'prepend_1 creates a new list, assigns it to _list and forgets the original'
    print '_list refers to the same object as _try -->', id(_list), _list
    _list = [element] + _list
    print '_list now refers to a different object -->', id(_list), _list

def prepend_2(element, _list):
    print 'prepend_2 updates the existing list'
    print '_list refers to the same object as _try -->', id(_list), _list
    _list.insert(0, element)
    print '_list still refers to the same object as _try -->', id(_list), _list

_try = [1,2,3]
print '_try is assigned -->', id(_try), _try
prepend_1(0, _try)
print '_try is the same object and is not updated -->', id(_try), _try
prepend_2(0, _try)
print '_try is the same object and is updated -->', id(_try), _try
print _try

当我运行它时,你可以看到对象与引用它们的变量之间的关系

_try is assigned --> 18234472 [1, 2, 3]
prepend_1 creates a new list, assigns it to _list and forgets the original
_list refers to the same object as _try --> 18234472 [1, 2, 3]
_list now refers to --> 18372440 [0, 1, 2, 3]
_try is the same object and is not updated --> 18234472 [1, 2, 3]
prepend_2 updates the existing list
_list refers to the same object as _try --> 18234472 [1, 2, 3]
_list still refers to the same object as _try --> 18234472 [0, 1, 2, 3]
_try is the same object and is updated --> 18234472 [0, 1, 2, 3]
[0, 1, 2, 3]

【讨论】:

  • Python 中没有传递引用。
  • @newacct - 取决于您使用的术语“参考”的迂腐重载。例如,当 list 被传递给函数时,它的 reference count 会增加。我发现谈论“按引用传递”是描述正在发生的事情的好方法,特别是因为它与 C/C++ 程序员有关,他们考虑的是值而不是指向值的指针。
  • 好的,所以你提到了 C/C++。 Python 中的值在语义上与 C/C++ 中的指向对象的指针相同。当你传递一个指针时,这在 C/C++ 中不称为 pass-by-reference。
  • @tdelaney - 当我说 _list=list2 虽然局部变量 _list 改变了全局变量 _try i> 不变。但是当我写 _list.insert(0,element) _list changes (这很好)以及 _try 也发生了变化(这令人不安我)。请澄清一下。
  • @coderkd10 - 变量和它指向的对象是不同的野兽。可能很难描述,因为对象是无名实体——它们被命名变量或其他对象引用。 _try 和 _list 开始指向同一个对象。 _list = [element] + _list 创建一个新对象并重新分配_list,让_try 指向原始未更改的对象。 _list.insert(0, element) 更新 _try 和 _list 指向的原始对象。
【解决方案2】:

Python 只是 PASS-BY-VALUE

就像 Java 中的非基元一样,Python 中的所有值都是引用,即指向对象的指针。就像在 Java 中一样,它们是按值分配和传递的。总是。

我的定义是:如果一个参数的简单赋值(=)与调用作用域内传递的变量的简单赋值(=)效果相同,那么就是pass-by-reference。如果对参数的简单赋值(=)对调用范围内传递的变量没有影响,则它是按值传递。在 Java、Python、Ruby、Scheme、Go、C、JavaScript、Smalltalk 和许多其他语言中是后者。

【讨论】:

  • @MartinPieters:我的疑问是:虽然函数 prepend 中名为“list”的局部变量更改为 [0,1,2,3] 那么为什么全局变量“tryList”没有改变?
  • @coderkd10:你所说的“改变”是什么意思?如果您的意思是变量tryList,它是一个指向对象的指针,它不会改变(指向任何不同的东西),因为没有分配给它。如果您的意思是tryList 指向的对象没有以某种方式发生变异,那是因为没有人在其上调用任何东西来更改它。该对象的唯一用途是作为prepend 内的+ 运算符的参数。但是,在appendList 中,您在对象上调用了.append(),这是一个更改对象的方法。
  • 读者我想推荐你看这篇文章,它更清楚:stackoverflow.com/questions/11222440/…
【解决方案3】:

不是按值传递。 python 中的所有内容都是通过引用传递的。

def prepend(element,list):
    list = [element] + list  # Here new memory is allocated for "list" ,
                              # note list is here a local variable. 

请不要使用'list'作为变量名,它是数据类型名称的关键字。

【讨论】:

  • Python 只是传值。 Python 中没有传递引用。
【解决方案4】:

“按对象调用” 这应该回答你的问题。 http://effbot.org/zone/call-by-object.html

猜你喜欢
  • 1970-01-01
  • 2017-03-21
  • 2013-05-16
  • 2017-08-12
  • 2013-01-14
  • 2011-02-24
  • 1970-01-01
  • 2011-07-31
  • 1970-01-01
相关资源
最近更新 更多