我写了此类进行测试:
class PassByReference:
def __init__(self):
self.variable = 'Original'
self.change(self.variable)
print(self.variable)
def change(self, var):
var = 'Changed'
当我尝试创建一个实例时,输出为原始
。因此,python中的参数似乎是按值传递的。那是对的吗?我如何修改代码以获取通过参考的效果,以使输出更改?
有时人们会惊讶地发现 x = 1
,其中 x
是参数名称,不会影响呼叫者的参数,而是代码之类的代码。 x [0] = 1 做。发生这种情况是因为 item sissmentment 和切片分配是突变现有对象而不是重新分配变量的方法,尽管 = << /代码>语法。 呼叫者所感知的某些参数,而不是其他参数?
请参阅为什么函数可以修改 >另请参见“通过参考传递与通过价值传递的传递之间有什么区别?对于重要的,语言 - aggnostic术语讨论。
I wrote this class for testing:
class PassByReference:
def __init__(self):
self.variable = 'Original'
self.change(self.variable)
print(self.variable)
def change(self, var):
var = 'Changed'
When I tried creating an instance, the output was Original
. So it seems like parameters in Python are passed by value. Is that correct? How can I modify the code to get the effect of pass-by-reference, so that the output is Changed
?
Sometimes people are surprised that code like x = 1
, where x
is a parameter name, doesn't impact on the caller's argument, but code like x[0] = 1
does. This happens because item assignment and slice assignment are ways to mutate an existing object, rather than reassign a variable, despite the =
syntax. See Why can a function modify some arguments as perceived by the caller, but not others? for details.
See also What's the difference between passing by reference vs. passing by value? for important, language-agnostic terminology discussion.
发布评论
评论(30)
参数为通过分配传递。背后的基本原理是双重的:
:
如果将可变对象传递到方法中,则该方法会引入对该对象的引用,并且可以将其突变为心脏的喜悦,但是如果您重新启动该方法中的参考,则外部范围将对此一无所知,完成后,外部引用仍将指向原始对象。
如果您将不变的对象传递到方法中,那么您仍然无法重新启动外部引用,甚至无法突变对象。
为了使它更加清楚,让我们有一些例子。
列表 - 一种可变类型
让我们尝试修改传递给方法的列表:
输出:
由于传递的参数是对
offecter_list
的引用,而不是它的副本,我们可以使用突变列表方法对其进行更改,并将更改反映在外部范围中。现在让我们看看当我们尝试更改作为参数传递的参考时会发生什么:
输出:
因为
the_list
参数是按值传递的,将新列表分配给该方法之外的代码无效。the_list
是outer_list
参考的副本,我们有the_list
指向新列表,但是没有办法更改<<代码> outer_list 指向。字符串 - 不变的类型
它是不变的,因此现在我们无能为力更改字符串的内容
,让我们尝试更改参考
输出:
再次,因为<代码> the_string 参数是按值传递的,为其分配了一个新字符串,没有效果。
the_string
是outer_string
参考的副本,我们有the_string
指向一个新字符串,但是没有办法更改<代码> outer_string 指向。我希望这能使事情有所清晰。
编辑:已经注意到,这没有回答@David最初问的问题:“我可以做些什么以通过实际参考来传递变量?”。让我们对此进行努力。
我们如何解决这个问题?
正如 @Andrea的答案所示,您可以返回新值。这不会改变事物传递的方式,但可以让您获得想要返回的信息:
如果您真的想避免使用返回值,则可以创建一个类以保持价值并将其传递到功能中或使用现有类,例如列表:
虽然这似乎有些麻烦。
Arguments are passed by assignment. The rationale behind this is twofold:
So:
If you pass a mutable object into a method, the method gets a reference to that same object and you can mutate it to your heart's delight, but if you rebind the reference in the method, the outer scope will know nothing about it, and after you're done, the outer reference will still point at the original object.
If you pass an immutable object to a method, you still can't rebind the outer reference, and you can't even mutate the object.
To make it even more clear, let's have some examples.
List - a mutable type
Let's try to modify the list that was passed to a method:
Output:
Since the parameter passed in is a reference to
outer_list
, not a copy of it, we can use the mutating list methods to change it and have the changes reflected in the outer scope.Now let's see what happens when we try to change the reference that was passed in as a parameter:
Output:
Since the
the_list
parameter was passed by value, assigning a new list to it had no effect that the code outside the method could see. Thethe_list
was a copy of theouter_list
reference, and we hadthe_list
point to a new list, but there was no way to change whereouter_list
pointed.String - an immutable type
It's immutable, so there's nothing we can do to change the contents of the string
Now, let's try to change the reference
Output:
Again, since the
the_string
parameter was passed by value, assigning a new string to it had no effect that the code outside the method could see. Thethe_string
was a copy of theouter_string
reference, and we hadthe_string
point to a new string, but there was no way to change whereouter_string
pointed.I hope this clears things up a little.
EDIT: It's been noted that this doesn't answer the question that @David originally asked, "Is there something I can do to pass the variable by actual reference?". Let's work on that.
How do we get around this?
As @Andrea's answer shows, you could return the new value. This doesn't change the way things are passed in, but does let you get the information you want back out:
If you really wanted to avoid using a return value, you could create a class to hold your value and pass it into the function or use an existing class, like a list:
Although this seems a little cumbersome.
问题来自对Python中什么变量的误解。如果您习惯了大多数传统语言,则具有以下顺序中发生的情况的心理模型:
您相信
a
是存储值1
的存储位置,然后更新以存储值2
。这不是Python的工作方式。相反,a
开始作为对具有值1
的对象的引用,然后将其重新分配为具有值2
的对象的引用。即使a
不再引用第一个对象,这两个对象也可以继续共存。实际上,它们可以通过程序中的任何其他参考文献共享。当您调用带有参数的函数时,创建了一个新的引用,它是指传递的对象。这与函数调用中使用的引用分开,因此无法更新该参考新对象。在您的示例中:
self.variable
是字符串对象'原始'
的引用。调用更改
时,将第二个参考var
向对象创建。在函数内部,您可以将参考var
重新分配给其他字符串对象'更改'
,但是参考self.variable.variable
是独立的,并且不更改。解决此问题的唯一方法是通过一个可变的物体。因为这两个引用都涉及同一对象,所以对象的任何更改都反映在两个地方。
The problem comes from a misunderstanding of what variables are in Python. If you're used to most traditional languages, you have a mental model of what happens in the following sequence:
You believe that
a
is a memory location that stores the value1
, then is updated to store the value2
. That's not how things work in Python. Rather,a
starts as a reference to an object with the value1
, then gets reassigned as a reference to an object with the value2
. Those two objects may continue to coexist even thougha
doesn't refer to the first one anymore; in fact they may be shared by any number of other references within the program.When you call a function with a parameter, a new reference is created that refers to the object passed in. This is separate from the reference that was used in the function call, so there's no way to update that reference and make it refer to a new object. In your example:
self.variable
is a reference to the string object'Original'
. When you callChange
you create a second referencevar
to the object. Inside the function you reassign the referencevar
to a different string object'Changed'
, but the referenceself.variable
is separate and does not change.The only way around this is to pass a mutable object. Because both references refer to the same object, any changes to the object are reflected in both places.
我发现其他答案相当长且复杂,因此我创建了这个简单的图来解释Python处理变量和参数的方式。

I found the other answers rather long and complicated, so I created this simple diagram to explain the way Python treats variables and parameters.

它既不是逐个价值,也不是通过引用 - 它是逐个呼叫。请参阅Fredrik Lundh:
通过对象调用
这是一个重要的报价:
在您的示例中,当
更改
方法被称为 - 名称空间;var
在该名称空间内成为一个名称,对于字符串对象'原始'
。然后,该对象在两个名称空间中具有一个名称。接下来,var ='更改''
绑定var
与新的字符串对象,因此该方法的命名空间忘记了'Original'
。最后,该名称空间被遗忘了,字符串'更改'
以及其中。It is neither pass-by-value or pass-by-reference - it is call-by-object. See this, by Fredrik Lundh:
Call By Object
Here is a significant quote:
In your example, when the
Change
method is called--a namespace is created for it; andvar
becomes a name, within that namespace, for the string object'Original'
. That object then has a name in two namespaces. Next,var = 'Changed'
bindsvar
to a new string object, and thus the method's namespace forgets about'Original'
. Finally, that namespace is forgotten, and the string'Changed'
along with it.想想通过分配传递的东西而不是通过参考/按值。这样,总是很明显,只要您了解正常分配过程中会发生什么。
因此,将列表传递给函数/方法时,将列表分配给参数名称。附加列表将导致列表正在修改。重新分配列表内部该函数不会更改原始列表,因为:
由于无法修改不变的类型,它们似乎是按值传递的表示将int分配给函数的参数。您只能将其重新分配,但是它不会改变原始变量值。
Think of stuff being passed by assignment instead of by reference/by value. That way, it is always clear, what is happening as long as you understand what happens during the normal assignment.
So, when passing a list to a function/method, the list is assigned to the parameter name. Appending to the list will result in the list being modified. Reassigning the list inside the function will not change the original list, since:
Since immutable types cannot be modified, they seem like being passed by value - passing an int into a function means assigning the int to the function's parameter. You can only ever reassign that, but it won't change the original variables value.
Python中没有变量
了解参数传递的关键是停止思考“变量”。 Python中有名称和对象,一起
看起来像变量,但总是区分三个很有用。
这就是其中的全部。可变性与这个问题无关。
示例:
这将名称
a
绑定到包含值1的类型对象。这将名称
b
绑定到名称x <的同一对象。 /代码>当前绑定到。
之后,名称
b
与名称x
无关。请参阅节 3.1 https://docs.python.org/3/reference/executermodel.html#naming-and-binding“ rel =“ noreferrer”> 4.2 python 3语言参考。
如何在问题中显示的代码中读取示例
,语句
self.change(self.variable)
绑定名称var
(在函数范围内更改
)到保存值'原始'
的对象和分配var ='更改''
(在函数主体中更改
)再次分配相同的名称:到其他对象(碰巧也容纳一个字符串,但可能完全是其他对象)。如何通过引用传递,
因此,如果您要更改的内容是一个可变的对象,则没有问题,因为一切都是通过参考有效传递的。
如果是 noreferrer“> norReferrer”>不可能 bool,number,string),要走的方法是将其包裹在可变的对象中。
对此的快速解决方案是一个单元素列表(而不是
self.variable
,Pass[self.variable]
,在函数Modify中var [0]
)。越 pythonic 方法是引入一个琐碎的,单位的属性类。该功能接收类的实例并操纵属性。
There are no variables in Python
The key to understanding parameter passing is to stop thinking about "variables". There are names and objects in Python and together they
appear like variables, but it is useful to always distinguish the three.
That is all there is to it. Mutability is irrelevant to this question.
Example:
This binds the name
a
to an object of type integer that holds the value 1.This binds the name
b
to the same object that the namex
is currently bound to.Afterward, the name
b
has nothing to do with the namex
anymore.See sections 3.1 and 4.2 in the Python 3 language reference.
How to read the example in the question
In the code shown in the question, the statement
self.Change(self.variable)
binds the namevar
(in the scope of functionChange
) to the object that holds the value'Original'
and the assignmentvar = 'Changed'
(in the body of functionChange
) assigns that same name again: to some other object (that happens to hold a string as well but could have been something else entirely).How to pass by reference
So if the thing you want to change is a mutable object, there is no problem, as everything is effectively passed by reference.
If it is an immutable object (e.g. a bool, number, string), the way to go is to wrap it in a mutable object.
The quick-and-dirty solution for this is a one-element list (instead of
self.variable
, pass[self.variable]
and in the function modifyvar[0]
).The more pythonic approach would be to introduce a trivial, one-attribute class. The function receives an instance of the class and manipulates the attribute.
Effbot(又名Fredrik Lundh)将Python的可变传递样式描述为呼叫: https://web.archive.org/web/2020201111195827/http:/http://effbot.org/zone/call-by-by-byby-object.htm
对象已分配在堆和指针上可以通过任何地方传递。
当您进行诸如
x = 1000
之类的作业时,创建了一个字典条目,将当前名称空间中的字符串“ x”映射到指向包含一千个整数对象的指针。使用
x = 2000
更新“ x”时,将创建一个新的整数对象,并且词典已更新以指向新对象。旧的一千个对象没有变化(并且可能还活着,具体取决于其他任何内容)。。
当您进行新作业(例如
y = x
)时,创建了一个新的字典条目“ y”,指向与“ x”的条目相同的对象。字符串和整数之类的对象是不变的。这仅意味着在创建对象后没有任何方法可以更改该方法。例如,一旦创建了一千个整数对象,它将永远不会改变。数学是通过创建新的整数对象完成的。
列表之类的对象是可变。这意味着可以通过指向对象的任何内容来更改对象的内容。例如,
x = []; y = x; X.Append(10);打印y
将打印[10]
。创建了空列表。 “ x”和“ y”都指向同一列表。 append 方法突变(更新)列表对象(例如将记录添加到数据库),并且“ x”和“ y”都可以看到结果(就像数据库更新一样,可见与该数据库的每个连接)。希望这为您阐明问题。
Effbot (aka Fredrik Lundh) has described Python's variable passing style as call-by-object: https://web.archive.org/web/20201111195827/http://effbot.org/zone/call-by-object.htm
Objects are allocated on the heap and pointers to them can be passed around anywhere.
When you make an assignment such as
x = 1000
, a dictionary entry is created that maps the string "x" in the current namespace to a pointer to the integer object containing one thousand.When you update "x" with
x = 2000
, a new integer object is created and the dictionary is updated to point at the new object. The old one thousand object is unchanged (and may or may not be alive depending on whether anything else refers to the object).When you do a new assignment such as
y = x
, a new dictionary entry "y" is created that points to the same object as the entry for "x".Objects like strings and integers are immutable. This simply means that there are no methods that can change the object after it has been created. For example, once the integer object one-thousand is created, it will never change. Math is done by creating new integer objects.
Objects like lists are mutable. This means that the contents of the object can be changed by anything pointing to the object. For example,
x = []; y = x; x.append(10); print y
will print[10]
. The empty list was created. Both "x" and "y" point to the same list. The append method mutates (updates) the list object (like adding a record to a database) and the result is visible to both "x" and "y" (just as a database update would be visible to every connection to that database).Hope that clarifies the issue for you.
从技术上讲, python始终使用参考值。我要重复我的其他答案支持我的陈述。
Python始终使用传递值。没有任何例外。任何变量分配都意味着复制参考值。不例外。任何变量都是绑定到参考值的名称。总是。
您可以将参考值视为目标对象的地址。使用时将自动删除该地址。这样,使用参考值,似乎您直接与目标对象一起使用。但是,介于两者之间总是有一个参考,要多跳到目标。
这是一个示例,证明Python使用通过参考传递:
参数的示例”>
您可以使用
id()
内置功能以了解参考值是什么(即目标对象的地址)。在编译的语言中,变量是能够捕获类型值的内存空间。在Python中,一个变量是与参考变量绑定的名称(内部捕获为字符串),该名称将参考值保存到目标对象。该变量的名称是内部字典中的键,该字典项目的值部分存储了对目标的参考值。
参考值隐藏在Python中。没有任何用于存储参考值的明确用户类型。但是,您可以将列表元素(或任何其他合适的容器类型中的元素)用作参考变量,因为所有容器都会将元素存储为对目标对象的引用。换句话说,元素实际上不包含在容器内部 - 只有对元素的引用。
Technically, Python always uses pass by reference values. I am going to repeat my other answer to support my statement.
Python always uses pass-by-reference values. There isn't any exception. Any variable assignment means copying the reference value. No exception. Any variable is the name bound to the reference value. Always.
You can think about a reference value as the address of the target object. The address is automatically dereferenced when used. This way, working with the reference value, it seems you work directly with the target object. But there always is a reference in between, one step more to jump to the target.
Here is the example that proves that Python uses passing by reference:
If the argument was passed by value, the outer
lst
could not be modified. The green are the target objects (the black is the value stored inside, the red is the object type), the yellow is the memory with the reference value inside -- drawn as the arrow. The blue solid arrow is the reference value that was passed to the function (via the dashed blue arrow path). The ugly dark yellow is the internal dictionary. (It actually could be drawn also as a green ellipse. The colour and the shape only says it is internal.)You can use the
id()
built-in function to learn what the reference value is (that is, the address of the target object).In compiled languages, a variable is a memory space that is able to capture the value of the type. In Python, a variable is a name (captured internally as a string) bound to the reference variable that holds the reference value to the target object. The name of the variable is the key in the internal dictionary, the value part of that dictionary item stores the reference value to the target.
Reference values are hidden in Python. There isn't any explicit user type for storing the reference value. However, you can use a list element (or element in any other suitable container type) as the reference variable, because all containers do store the elements also as references to the target objects. In other words, elements are actually not contained inside the container -- only the references to elements are.
我通常使用的一个简单的技巧就是将其包装在列表中:(
是的,这可能会带来不便,但有时可以简单地做到这一点。)
A simple trick I normally use is to just wrap it in a list:
(Yeah I know this can be inconvenient, but sometimes it is simple enough to do this.)
您在这里得到了一些非常好的答案。
You got some really good answers here.
在这种情况下> var 。它不再指向
self.variable
。 修改var
和self.variable
的数据结构将会发生什么以下代码段显示如果您 进一步澄清。
In this case the variable titled
var
in the methodChange
is assigned a reference toself.variable
, and you immediately assign a string tovar
. It's no longer pointing toself.variable
. The following code snippet shows what would happen if you modify the data structure pointed to byvar
andself.variable
, in this case a list:I'm sure someone else could clarify this further.
Python的通过分配方案与C ++的参考参数选项并不完全相同,但事实证明,它与实践中C语言(和其他)的参数模型非常相似:
字典也通过对象参考传递,这与C的方式相似
将数组作为指针作为指针 - 可以在函数中更改位置的对象,
很像C数组。
Python’s pass-by-assignment scheme isn’t quite the same as C++’s reference parameters option, but it turns out to be very similar to the argument-passing model of the C language (and others) in practice:
and dictionaries are also passed by object reference, which is similar to the way C
passes arrays as pointers—mutable objects can be changed in place in the function,
much like C arrays.
这里的答案有很多见解,但我认为这里没有明确提及另一点。引用python文档 python中本地和全局变量的规则是什么?
即使将可变的对象传递到一个函数时,仍然适用。对我来说,它清楚地说明了分配给对象和在函数中对象上操作的行为差异的原因。
给出:
对未声明全局的全局变量的分配,因此创建了一个新的本地对象,并打破了指向原始对象的链接。
There are a lot of insights in answers here, but I think an additional point is not clearly mentioned here explicitly. Quoting from Python documentation What are the rules for local and global variables in Python?
Even when passing a mutable object to a function this still applies. And to me it clearly explains the reason for the difference in behavior between assigning to the object and operating on the object in the function.
gives:
The assignment to an global variable that is not declared global therefore creates a new local object and breaks the link to the original object.
如您所言,您需要有一个可变的对象,但让我建议您检查全局变量,因为它们可以帮助您甚至解决此类问题!
http://docs.python.org/3/faq/programming.html#what-are-the-the-the-rules-for-local-and-global-global-variables-in-python
示例:
As you can state you need to have a mutable object, but let me suggest you to check over the global variables as they can help you or even solve this kind of issue!
http://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python
example:
这是对概念的简单(我希望)解释 python中使用的对象。
每当您将对象传递到函数时,对象本身就会传递(Python中的对象实际上是您称之为其他编程语言中的值),而不是对此对象的引用。换句话说,当您调用时:
实际对象 - [0,1](将其称为其他编程语言中的值)正在传递。因此,实际上,函数
change_me
将尝试执行类似的操作:显然不会将传递给该函数的对象更改。如果函数看起来像这样:
那么调用将导致:
显然会更改对象。 此答案很好地解释了这一点。
Here is the simple (I hope) explanation of the concept
pass by object
used in Python.Whenever you pass an object to the function, the object itself is passed (object in Python is actually what you'd call a value in other programming languages) not the reference to this object. In other words, when you call:
The actual object - [0, 1] (which would be called a value in other programming languages) is being passed. So in fact the function
change_me
will try to do something like:which obviously will not change the object passed to the function. If the function looked like this:
Then the call would result in:
which obviously will change the object. This answer explains it well.
除了对这些东西在Python中工作的所有很好的解释之外,我看不到这个问题的简单建议。正如您似乎确实创建对象和实例一样,处理实例变量并更改它们的Pythonic方法是:
在实例方法中,您通常请参考
self
访问实例属性。在__ Init __
中设置实例属性并在实例方法中读取或更改它们是正常的。这也是为什么您将self
作为第一个参数将其传递给def Change
的原因。另一个解决方案是创建这样的静态方法:
Aside from all the great explanations on how this stuff works in Python, I don't see a simple suggestion for the problem. As you seem to do create objects and instances, the Pythonic way of handling instance variables and changing them is the following:
In instance methods, you normally refer to
self
to access instance attributes. It is normal to set instance attributes in__init__
and read or change them in instance methods. That is also why you passself
as the first argument todef Change
.Another solution would be to create a static method like this:
我使用以下方法将一些Fortran代码快速转换为Python。的确,由于提出了原始问题,这不是通过引用的,但在某些情况下这是一个简单的解决方法。
I used the following method to quickly convert some Fortran code to Python. True, it's not pass by reference as the original question was posed, but it is a simple workaround in some cases.
要通过引用模拟传递对象,请将其包装在单项列表中:
分配给列表的元素会突变列表而不是重新分配名称。由于列表本身具有参考语义,因此更改反映在呼叫者中。
To simulate passing an object by reference, wrap it in a one-item list:
Assigning to an element of the list mutates the list rather than reassigning a name. Since the list itself has reference semantics, the change is reflected in the caller.
由于似乎无处提到了一种模拟参考的方法,例如C ++是使用“更新”函数并传递该功能而不是实际变量(或更确切地说,“名称”):
这对于“ out--仅引用”或在具有多个线程 /进程的情况下(通过使更新功能线程 /多处理安全)。
显然,以上不允许读取仅更新值。
Since it seems to be nowhere mentioned an approach to simulate references as known from e.g. C++ is to use an "update" function and pass that instead of the actual variable (or rather, "name"):
This is mostly useful for "out-only references" or in a situation with multiple threads / processes (by making the update function thread / multiprocessing safe).
Obviously the above does not allow reading the value, only updating it.
鉴于Python处理值和引用的方式,您可以参考任意实例属性的唯一方法是按名称:
在实际代码中,您当然会添加错误检查DICT查找。
Given the way Python handles values and references to them, the only way you can reference an arbitrary instance attribute is by name:
In real code you would, of course, add error checking on the dict lookup.
由于您的示例恰好是面向对象的,因此您可以进行以下更改以获得类似的结果:
Since your example happens to be object-oriented, you could make the following change to achieve a similar result:
您只能将一个空的类用作存储参考对象的实例,因为内部对象属性存储在实例字典中。请参阅示例。
You can merely use an empty class as an instance to store reference objects because internally object attributes are stored in an instance dictionary. See the example.
由于字典是通过引用传递的,因此您可以使用dict变量在其中存储任何引用值。
Since dictionaries are passed by reference, you can use a dict variable to store any referenced values inside it.
虽然通过参考可以很好地适合Python,因此很少使用,但实际上有些解决方法可以使对象当前分配给本地变量,甚至可以从称为函数的内部重新分配局部变量。
基本思想是具有可以执行该访问权限的函数,并且可以作为对象传递到其他功能中或存储在类中。
一种方法是在包装器函数中使用
Global
(对于全局变量)或非局部
(对于函数中的本地变量)。相同的想法适用于阅读和
del
et and and a a acte a a varible。仅需阅读即可使用
lambda:x
的较短方法,该方法返回可呼叫的可呼叫,该可调用时返回返回x的当前值。这有点像遥远过去的语言中使用的“呼叫”。传递3个包装器访问变量有点笨拙,因此可以将它们包裹到具有代理属性的类中:
Pythons“反射”支持使得获得能够在给定范围中重新分配名称/变量的对象不明确定义功能在该范围中:
此处
byref
类包含字典访问。因此,属性访问包装
被转换为传递字典中的项目访问。通过传递内置当地人的结果
和本地变量的名称,最终可以访问本地变量。截至3.5起,Python文档建议更改字典可能不起作用,但似乎对我有用。While pass by reference is nothing that fits well into Python and should be rarely used, there are some workarounds that actually can work to get the object currently assigned to a local variable or even reassign a local variable from inside of a called function.
The basic idea is to have a function that can do that access and can be passed as object into other functions or stored in a class.
One way is to use
global
(for global variables) ornonlocal
(for local variables in a function) in a wrapper function.The same idea works for reading and
del
eting a variable.For just reading, there is even a shorter way of just using
lambda: x
which returns a callable that when called returns the current value of x. This is somewhat like "call by name" used in languages in the distant past.Passing 3 wrappers to access a variable is a bit unwieldy so those can be wrapped into a class that has a proxy attribute:
Pythons "reflection" support makes it possible to get a object that is capable of reassigning a name/variable in a given scope without defining functions explicitly in that scope:
Here the
ByRef
class wraps a dictionary access. So attribute access towrapped
is translated to a item access in the passed dictionary. By passing the result of the builtinlocals
and the name of a local variable, this ends up accessing a local variable. The Python documentation as of 3.5 advises that changing the dictionary might not work, but it seems to work for me.Python中的通过参考与C ++/Java中的参考概念完全不同。
java和c#:原始类型(包括字符串)按值(复制)通过。参考类型是通过参考(地址副本)传递的,因此呼叫者可见在调用函数中所做的所有更改。
c ++:允许通过引用或通过传递。如果通过引用传递参数,则可以根据是否传递为const进行修改。但是,无论是否const,参数都将对对象的引用和引用无法分配给指向所谓函数中的另一个对象。
python:
Python是“通过对象引用”,经常说:“对象引用是按价值传递的。” (在这里阅读)。呼叫者和函数都涉及同一对象,但是该函数中的参数是一个新变量,它只是在呼叫者中保存对象的副本。像C ++一样,参数可以修改或不在功能中。这取决于传递的对象类型。例如,无法在调用函数中修改不变的对象类型,而可变的对象可以更新或重新定位。
更新或重新定位/重新定位之间的关键差异是可变变量的是,更新值会反映在调用函数中,而重新初始化值则没有。将新对象分配到可变变量的任何分配的范围是Python中该函数的局部性。 @Blair-Conrad提供的示例很高兴理解这一点。
Pass-by-reference in Python is quite different from the concept of pass by reference in C++/Java.
Java and C#: primitive types (including string) pass by value (copy). A reference type is passed by reference (address copy), so all changes made in the parameter in the called function are visible to the caller.
C++: Both pass-by-reference or pass-by-value are allowed. If a parameter is passed by reference, you can either modify it or not depending upon whether the parameter was passed as const or not. However, const or not, the parameter maintains the reference to the object and reference cannot be assigned to point to a different object within the called function.
Python:
Python is “pass-by-object-reference”, of which it is often said: “Object references are passed by value.” (read here). Both the caller and the function refer to the same object, but the parameter in the function is a new variable which is just holding a copy of the object in the caller. Like C++, a parameter can be either modified or not in function. This depends upon the type of object passed. For example, an immutable object type cannot be modified in the called function whereas a mutable object can be either updated or re-initialized.
A crucial difference between updating or reassigning/re-initializing the mutable variable is that updated value gets reflected back in the called function whereas the reinitialized value does not. The scope of any assignment of new object to a mutable variable is local to the function in the python. Examples provided by @blair-conrad are great to understand this.
我发现其他答案有些混乱,我不得不努力掌握这些概念。因此,我试图将答案放在我的语言中。如果其他答案也使您感到困惑,这可能会为您提供帮助。因此,答案就像是这样的 -
当您创建列表时 -
实际上是在创建类列表的对象:
在此,my_list只是由由构造函数创建的对象的内存地址(例如,140707924412080)给出的名称。 “列表”类。
的方法时,
当您将此列表传递给定义为对同一内存地址的另一个引用 创建了140707924412080。因此,当您使用附加方法对对象进行任何更改/突变时,它也会反映在my_method1之外。因为,外部列表my_list和local_list都在引用相同的内存地址。
另一方面,当您将同一列表传递给以下方法时,
该过程的前半部分保持不变。即创建了一个新的参考/名称local_list2,指向同一内存地址14070707924412080。但是,当您创建一个新列表[1,2,3,4]时,“列表”类的构造函数再次称为创建对象。该新对象具有完全不同的内存地址,例如140707924412112。当您将local_list2分配给[1,2,3,4]时,现在local_list2名称是指一个新的内存地址,该地址为14070707924412112。由于在整个过程中,没有对放置在内存地址的对象进行任何更改,它仍然不受影响。
换句话说,本着“其他语言有变量,python有名字”的精神。这意味着在其他语言中,变量被引用在内存中的固定地址。这意味着,在C ++中,如果您通过
存储“ 1”的值“ 1”的内存地址重新分配一个变量,则现在持有值'2',因此,值'1'完全丢失了。而在Python中,由于所有内容都是一个对象,因此“ a”较早地引用了存储类“ int”对象的内存地址,该对象又存储了值'1'。但是,在重新分配后,它指的是一个完全不同的内存地址,该存储地址存储了新创建的“ int”“持有值'2'的对象”。
希望它有帮助。
I found other answers a little bit confusing and I had to struggle a while to grasp the concepts. So, I am trying to put the answer in my language. It may help you if other answers are confusing to you too. So, the answer is like this-
When you create a list-
you are actually creating an object of the class list:
Here, my_list is just a name given to the memory address (e.g., 140707924412080) of the object created by the constructor of the 'list' class.
When you pass this list to a method defined as
another reference to the same memory address 140707924412080 is created. So, when you make any changes/mutate to the object by using append method, it is also reflected outside the my_method1. Because, both the outer list my_list and local_list are referencing the same memory address.
On the other hand, when you pass the same list to the following method,
the first half of the process remains the same. i.e., a new reference/name local_list2 is created which points to the same memory address 140707924412080. But when you create a new list [1,2,3,4], the constructor of the 'list' class is called again and a new object is created. This new object has a completely different memory address, e.g., 140707924412112. When you assign local_list2 to [1,2,3,4], now the local_list2 name refers to a new memory address which is 140707924412112. Since in this entire process you have not made any changes to the object placed at memory address 140707924412080, it remains unaffected.
In other words, it is in the spirit that 'other languages have variables, Python have names'. That means in other languages, variables are referenced to a fixed address in memory. That means, in C++, if you reassign a variable by
the memory address where the value '1' was stored is now holding the value '2' And hence, the value '1' is completely lost. Whereas in Python, since everything is an object, earlier 'a' referred to the memory address that stores the object of class 'int' which in turn stores the value '1'. But, after reassignment, it refers to a completely different memory address that stores the newly created object of class 'int' holding the value '2'.
Hope it helps.
我是Python的新手,昨天开始(尽管我已经编程已有45年了)。
我之所以来这里是因为我写了一个功能,我想拥有两个所谓的外部参数。如果这只是一个外部参数,那么我现在就不会挂在检查Python中的参考/价值的工作方式时。我只会使用函数的返回值。但是,由于我需要两个这样的外参数,所以我觉得我需要解决它。
在这篇文章中,我将展示如何解决自己的情况。也许来到这里的其他人可能会发现它很有价值,即使它并不是对主题问题的答案。经验丰富的Python程序员当然已经知道我使用的解决方案,但这对我来说是新的。
从这里的答案中,我可以很快看到Python在这方面的工作类似于JavaScript,并且如果您想要参考功能,则需要使用解决方法。
但是后来我在python中发现了一些我以前看不到其他语言的东西,也就是说,您可以以一种简单的逗号分隔的方式从函数中返回多个值,
这样同样,在呼叫方面处理它,这
对我来说足够好,我很满意。无需使用一些解决方法。
在其他语言中,您当然也可以返回许多值,但通常在对象中,您需要相应地调整呼叫端。
python的做法很简单。
如果您想通过参考更多地模仿,则可以按以下方式执行:
这给出了此结果
I am new to Python, started yesterday (though I have been programming for 45 years).
I came here because I was writing a function where I wanted to have two so-called out-parameters. If it would have been only one out-parameter, I wouldn't get hung up right now on checking how reference/value works in Python. I would just have used the return value of the function instead. But since I needed two such out-parameters I felt I needed to sort it out.
In this post I am going to show how I solved my situation. Perhaps others coming here can find it valuable, even though it is not exactly an answer to the topic question. Experienced Python programmers of course already know about the solution I used, but it was new to me.
From the answers here I could quickly see that Python works a bit like JavaScript in this regard, and that you need to use workarounds if you want the reference functionality.
But then I found something neat in Python that I don't think I have seen in other languages before, namely that you can return more than one value from a function, in a simple comma-separated way, like this:
and that you can handle that on the calling side similarly, like this
That was good enough for me and I was satisfied. There isn't any need to use some workaround.
In other languages you can of course also return many values, but then usually in the from of an object, and you need to adjust the calling side accordingly.
The Python way of doing it was nice and simple.
If you want to mimic by reference even more, you could do as follows:
which gives this result
另外,您可以使用 ctypes 看起来像这样的东西
: Python整数,显然是通过参考通过的。但是,您必须小心,因为可能会发生奇怪的事情,因此不建议这样做。
Alternatively, you could use ctypes which would look something like this:
As a is a c int and not a Python integer and apparently passed by reference. However, you have to be careful as strange things could happen, and it is therefore not advised.
使用 dataclasses 。另外,它允许您应用类型限制(又称“类型提示”)。
我同意人们的看法,在大多数情况下,您最好考虑不要使用它。
但是,当我们谈论 上下文 ,这是值得的知道这种方式。
您可以设计一个明确的上下文类。当原型设计时,我更喜欢数据类别,只是因为它很容易来回序列化。
Use dataclasses. Also, it allows you to apply type restrictions (aka "type hints").
I agree with folks that in most cases you'd better consider not to use it.
And yet, when we're talking about contexts, it's worth to know that way.
You can design an explicit context class though. When prototyping, I prefer dataclasses, just because it's easy to serialize them back and forth.
已经有很多很棒的答案(或者说意见),我已经阅读了,但是我想提到一个丢失的答案。一个来自 python的文档在FAQ部分中。我不知道发布此页面的日期,但这应该是我们的真实参考:
如果您有:
然后将其称为
fn(a)
,您正在做分配中的工作。因此,这发生了:创建了
某物
的附加引用。变量只是符号/名称/参考。他们没有“持有”任何东西。There are already many great answers (or let's say opinions) about this and I've read them, but I want to mention a missing one. The one from Python's documentation in the FAQ section. I don't know the date of publishing this page, but this should be our true reference:
If you have:
and you call it like
fn(a)
, you're doing exactly what you do in assignment. So this happens:An additional reference to
SOMETHING
is created. Variables are just symbols/names/references. They don't "hold" anything.