为什么 Python 中的列表参数表现得像 ByRef?

发布于 2024-08-07 00:06:41 字数 193 浏览 6 评论 0原文

这可能适用于大多数语言,但我不确定。我是 Python 的初学者,一直致力于 C# 和 VB 中的列表副本。但在 Python 中,每当我传递一个列表作为参数并使用“for i in range”进行枚举,然后更改列表参数的值时,输入值实际上会更改原始列表。我认为 Python 应该默认按值传递参数,这样一旦函数完成,我仍然拥有调用该函数之前的原始值。我缺少什么?谢谢!

This may be for most languages in general, but I'm not sure. I'm a beginner at Python and have always worked on copies of lists in C# and VB. But in Python whenever I pass a list as an argument and enumerate through using a "for i in range," and then change the value of the list argument, the input values actually changes the original list. I thought Python was supposed to pass arguments by value by default so that once the function is finished I still have the original values from before I called the function. What am I missing? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

笑忘罢 2024-08-14 00:06:41

Python 确实按值传递参数,但您收到的值是引用的副本(顺便说一句,这与 C#、VB.NET 和 Java 的行为方式完全相同)。

这是要记住的重要事情:

对象不是通过引用传递的 - 对象引用是通过值传递的

由于您拥有该引用的副本,因此对该引用所指向内容的任何操作都将就像您持有原始引用本身一样。

Python does pass arguments by value but the value you are receiving is a copy of the reference (incidentally this is the exact same way that C#, VB.NET, and Java behave as well).

This is the important thing to remember:

Objects are not passed by reference - object references are passed by value.

Since you have a copy of the reference, any operation on what that reference points to will be just as if you were holding the original reference itself.

小梨窩很甜 2024-08-14 00:06:41

Python —— 就像 Java 对原始标量以外的任何东西所做的那样,以及 C# 和 VB.NET 对默认类型参数所做的那样,而不是装箱类型和 out / ref 参数 —— 传递“通过对象引用”(搜索该短语 < a href="http://en.wikipedia.org/wiki/Python_syntax_and_semantics" rel="nofollow noreferrer">此处——这是 Python 的架构师和创建者 Guido 用来解释参数传递概念的方式) 。

每个名字都是对某个对象的引用;传递名称(或任何其他表达式)作为参数只是创建对同一对象的另一个引用(函数体可以通过参数的名称访问该对象)。 ((不存在“对名称的引用”这样的东西:有名称,它们是对对象的一种引用,以及对象 - 句号))。

当您传递一个可变对象时,即具有变异方法的对象(例如列表),被调用的函数可以通过直接或间接调用其变异方法来改变该对象。 ((“间接”,我的意思是“通过运算符”——例如:

somelist[len(somelist):] = [whatever]

somelist.append(whatever) 完全相同。))

当您想要将列表传递到函数中,但是如果希望函数能够以任何方式改变该列表,则必须传递列表的副本而不是原始列表 - 就像在 Java、C# 中一样,VB.NET。

非常清楚重新绑定名称改变对象之间的区别。重新绑定名称(“barename”,即 -- 限定名称不同;-)影响该名称 -- 任何对象任何。例如:

def f1(alist):
  alist = [23]

def f2(alist):
  alist[:] = [23]

你能看出这两个函数之间的区别吗?一种是重新绑定barenamealist——对任何事情都没有任何影响。另一种是改变(改变、改变……)作为参数接收的列表对象——通过将其内容设置为单项列表,并以 int 作为其唯一项。 完全、完全不同的东西!!!

Python -- just like Java does for anything but primitive scalars, and like C# and VB.NET do for the default kind parameters as opposed to boxed types and out / ref parms -- passes "by object reference" (search for that phrase here -- it's how Guido, Python's architect and creator, uses to explain this argument-passing concept).

Every name is a reference to some object; passing a name (or any other expression) as an argument is just creating yet another reference to the same object (which the function body can access through the parameter's name). ((There's no such thing as "a reference to a name": there are names, which are one kind of reference to objects, and object -- period)).

When you're passing a mutable object, i.e. one which has mutating methods (like for example a list), the called function can mutate the object by calling, directly or indirectly, its mutating methods. ((By "indirectly", I mean "through operators" -- for example:

somelist[len(somelist):] = [whatever]

is exactly identical to somelist.append(whatever).))

When you want to pass a list into a function, but do not want the function to be able to mutate that list in any way, you must pass a copy of the list instead of the original -- just like in Java, C#, VB.NET.

Be very clear about the distinction between rebinding a name and mutating an object. Rebinding the name ("barename", that is -- qualified-names are different;-) only affects that name -- NOT any object whatsoever. For example:

def f1(alist):
  alist = [23]

def f2(alist):
  alist[:] = [23]

Can you spot the difference between these two functions? One is rebinding the barename alist -- without any effect whatsoever on anything. The other is mutating (altering, changing, ...) the list object it received as its argument -- by setting its content to be a one-item list with an int as its sole item. Completely, utterly different things!!!

ゃ懵逼小萝莉 2024-08-14 00:06:41

要添加到安德鲁的答案中,如果您想保留原始内容,则需要明确制作列表的副本。您可以使用复制模块来完成此操作,或者只是执行类似的操作

a = [1,2]
b = list(a)

由于复制对象通常意味着性能下降,因此我发现在较大的项目中显式使用复制模块很有帮助。这样,我可以轻松找到所有要使用更多内存的地方。

To add to Andrew's answer, you need to explicitly make a copy of a list if you want to retain the original. You can do this using the copy module, or just do something like

a = [1,2]
b = list(a)

Since copying objects usually implies a performance hit, I find it helpful to explicitly use the copy module in my larger projects. That way, I can easily find all the places where I'm going to use a bunch more memory.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文