简体   繁体   English

如何通过引用传递变量?

[英]How do I pass a variable by reference?

Are parameters passed by reference or by value?参数是按引用传递还是按值传递? How do I pass by reference so that the code below outputs 'Changed' instead of 'Original' ?我如何通过引用传递以便下面的代码输出'Changed'而不是'Original'

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change(self.variable)
        print(self.variable)

    def change(self, var):
        var = 'Changed'

Arguments are passed by assignment .参数通过 assignment 传递 The rationale behind this is twofold:这背后的理由是双重的:

  1. the parameter passed in is actually a reference to an object (but the reference is passed by value)传入的参数其实是一个对象的引用(但是引用是按值传递的)
  2. some data types are mutable, but others aren't有些数据类型是可变的,但有些不是

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 List - 可变类型

Let's try to modify the list that was passed to a method:让我们尝试修改传递给方法的列表:

def try_to_change_list_contents(the_list):
    print('got', the_list)
    the_list.append('four')
    print('changed to', the_list)

outer_list = ['one', 'two', 'three']

print('before, outer_list =', outer_list)
try_to_change_list_contents(outer_list)
print('after, outer_list =', outer_list)

Output:输出:

before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']

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.由于传入的参数是对outer_list的引用,而不是它的副本,我们可以使用 mutating list 方法对其进行更改,并将更改反映在外部范围中。

Now let's see what happens when we try to change the reference that was passed in as a parameter:现在让我们看看当我们尝试更改作为参数传入的引用时会发生什么:

def try_to_change_list_reference(the_list):
    print('got', the_list)
    the_list = ['and', 'we', 'can', 'not', 'lie']
    print('set to', the_list)

outer_list = ['we', 'like', 'proper', 'English']

print('before, outer_list =', outer_list)
try_to_change_list_reference(outer_list)
print('after, outer_list =', outer_list)

Output:输出:

before, outer_list = ['we', 'like', 'proper', 'English']
got ['we', 'like', 'proper', 'English']
set to ['and', 'we', 'can', 'not', 'lie']
after, outer_list = ['we', 'like', 'proper', 'English']

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.由于the_list参数是按值传递的,因此为它分配一个新列表对方法外部的代码无法看到的影响。 The the_list was a copy of the outer_list reference, and we had the_list point to a new list, but there was no way to change where outer_list pointed. the_listouter_list引用的副本,我们让the_list指向一个新列表,但无法更改outer_list指向的位置。

String - an immutable type String - 不可变类型

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现在,让我们尝试更改参考

def try_to_change_string_reference(the_string):
    print('got', the_string)
    the_string = 'In a kingdom by the sea'
    print('set to', the_string)

outer_string = 'It was many and many a year ago'

print('before, outer_string =', outer_string)
try_to_change_string_reference(outer_string)
print('after, outer_string =', outer_string)

Output:输出:

before, outer_string = It was many and many a year ago
got It was many and many a year ago
set to In a kingdom by the sea
after, outer_string = It was many and many a year ago

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.同样,由于the_string参数是按值传递的,因此为它分配一个新字符串对方法外部的代码没有任何影响。 The the_string was a copy of the outer_string reference, and we had the_string point to a new string, but there was no way to change where outer_string pointed. the_stringouter_string引用的副本,我们让the_string指向一个新字符串,但无法更改outer_string指向的位置。

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?".编辑:有人指出,这并没有回答@David 最初提出的问题,“我可以做些什么来通过实际引用传递变量吗?”。 Let's work on that.让我们继续努力。

How do we get around this?我们如何解决这个问题?

As @Andrea's answer shows, you could return the new value.正如@Andrea 的回答所示,您可以返回新值。 This doesn't change the way things are passed in, but does let you get the information you want back out:这不会改变传入的方式,但可以让你得到你想要的信息:

def return_a_whole_new_string(the_string):
    new_string = something_to_do_with_the_old_string(the_string)
    return new_string

# then you could call it like
my_string = return_a_whole_new_string(my_string)

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:如果您真的想避免使用返回值,您可以创建一个类来保存您的值并将其传递给函数或使用现有类,如列表:

def use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change):
    new_string = something_to_do_with_the_old_string(stuff_to_change[0])
    stuff_to_change[0] = new_string

# then you could call it like
wrapper = [my_string]
use_a_wrapper_to_simulate_pass_by_reference(wrapper)

do_something_with(wrapper[0])

Although this seems a little cumbersome.虽然这看起来有点麻烦。

The problem comes from a misunderstanding of what variables are in Python.问题来自对 Python 中的变量的误解。 If you're used to most traditional languages, you have a mental model of what happens in the following sequence:如果您习惯于大多数传统语言,那么您对以下顺序发生的事情有一个心智模型:

a = 1
a = 2

You believe that a is a memory location that stores the value 1 , then is updated to store the value 2 .您认为a是存储值1的内存位置,然后更新为存储值2 That's not how things work in Python.这不是 Python 中的工作方式。 Rather, a starts as a reference to an object with the value 1 , then gets reassigned as a reference to an object with the value 2 .相反, a开始是对值为1的对象的引用,然后被重新分配为对值为2的对象的引用。 Those two objects may continue to coexist even though a doesn't refer to the first one anymore;即使a不再引用第一个对象,这两个对象也可能继续共存; 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:在您的示例中:

def __init__(self):
    self.variable = 'Original'
    self.Change(self.variable)

def Change(self, var):
    var = 'Changed'

self.variable is a reference to the string object 'Original' . self.variable是对字符串对象'Original'的引用。 When you call Change you create a second reference var to the object.当您调用Change时,您会为该对象创建第二个引用var Inside the function you reassign the reference var to a different string object 'Changed' , but the reference self.variable is separate and does not change.在函数内部,您将引用var重新分配给不同的字符串对象'Changed' ,但引用self.variable是独立的并且不会更改。

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.因为两个引用都引用同一个对象,所以对对象的任何更改都会反映在两个位置。

def __init__(self):         
    self.variable = ['Original']
    self.Change(self.variable)

def Change(self, var):
    var[0] = 'Changed'

I found the other answers rather long and complicated, so I created this simple diagram to explain the way Python treats variables and parameters.我发现其他答案相当冗长和复杂,所以我创建了这个简单的图表来解释 Python 处理变量和参数的方式。 在此处输入图像描述

It is neither pass-by-value or pass-by-reference - it is call-by-object.它既不是按值传递也不是按引用传递 - 它是按对象调用。 See this, by Fredrik Lundh:看这个,Fredrik Lundh:

http://effbot.org/zone/call-by-object.htm http://effbot.org/zone/call-by-object.htm

Here is a significant quote:这是一个重要的报价:

"...variables [names] are not objects; they cannot be denoted by other variables or referred to by objects." “...变量 [名称]不是对象;它们不能由其他变量表示或由对象引用。”

In your example, when the Change method is called--a namespace is created for it;在您的示例中,当调用Change方法时,会为其创建一个命名空间 and var becomes a name, within that namespace, for the string object 'Original' .并且var成为该名称空间内字符串对象'Original'名称。 That object then has a name in two namespaces.然后该对象在两个命名空间中有一个名称。 Next, var = 'Changed' binds var to a new string object, and thus the method's namespace forgets about 'Original' .接下来, var = 'Changed'var绑定到一个新的字符串对象,因此方法的命名空间忘记了'Original' Finally, that namespace is forgotten, and the string 'Changed' along with it.最后,这个命名空间被遗忘了,字符串'Changed'也被遗忘了。

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:重新分配函数的列表不会更改原始列表,因为:

a = [1, 2, 3]
b = a
b.append(4)
b = ['a', 'b']
print a, b      # prints [1, 2, 3, 4] ['a', 'b']

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.由于无法修改不可变类型,它们似乎是按值传递的——将 int 传递给函数意味着将 int 分配给函数的参数。 You can only ever reassign that, but it won't change the original variables value.您只能重新分配它,但它不会更改原始变量值。

There are no variables in Python 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. Python 中有名称和对象,它们一起看起来像变量,但始终区分这三者是有用的。

  1. Python has names and objects. Python 有名称和对象。
  2. Assignment binds a name to an object.赋值将名称绑定到对象。
  3. Passing an argument into a function also binds a name (the parameter name of the function) to an object.将参数传递给函数还会将名称(函数的参数名称)绑定到对象。

That is all there is to it.这就是它的全部。 Mutability is irrelevant to this question.可变性与这个问题无关。

Example:例子:

a = 1

This binds the name a to an object of type integer that holds the value 1.这将名称a绑定到具有值 1 的整数类型的对象。

b = x

This binds the name b to the same object that the name x is currently bound to.这将名称b绑定到名称x当前绑定到的同一对象。 Afterward, the name b has nothing to do with the name x anymore.之后,名称b就与名称x无关了。

See sections 3.1 and 4.2 in the Python 3 language reference.请参阅 Python 3 语言参考中的第3.14.2节。

How to read the example in the question如何阅读问题中的示例

In the code shown in the question, the statement self.Change(self.variable) binds the name var (in the scope of function Change ) to the object that holds the value 'Original' and the assignment var = 'Changed' (in the body of function Change ) assigns that same name again: to some other object (that happens to hold a string as well but could have been something else entirely).在问题中显示的代码中,语句self.Change(self.variable)将名称var (在函数Change的范围内)绑定到保存值'Original'和赋值var = 'Changed'对象(在函数体Change )再次将相同的名称分配给其他对象(它恰好也包含一个字符串,但可能完全是其他东西)。

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 (eg 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 modify var[0] ).快速而简单的解决方案是一个单元素列表(而不是self.variable ,传递[self.variable]并在函数中修改var[0] )。
The more pythonic approach would be to introduce a trivial, one-attribute class.Pythonic的方法是引入一个简单的、单一属性的类。 The function receives an instance of the class and manipulates the attribute.该函数接收该类的一个实例并操作该属性。

Effbot (aka Fredrik Lundh) has described Python's variable passing style as call-by-object: http://effbot.org/zone/call-by-object.htm Effbot(又名 Fredrik Lundh)将 Python 的变量传递风格描述为按对象调用: 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.当您进行诸如x = 1000之类的赋值时,将创建一个字典条目,将当前命名空间中的字符串“x”映射到指向包含一千的整数对象的指针。

  • When you update "x" with x = 2000 , a new integer object is created and the dictionary is updated to point at the new object.当您使用x = 2000更新 "x" 时,会创建一个新的整数对象,并且字典会更新为指向新对象。 The old one thousand object is unchanged (and may or may not be alive depending on whether anything else refers to the object).旧的 1000 个对象没有改变(并且可能存在也可能不存在,具体取决于是否有其他对象引用该对象)。

  • 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".当您执行新的赋值(例如y = x )时,会创建一个新的字典条目“y”,它指向与“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例如, x = []; y = x; x.append(10); print y x = []; y = x; x.append(10); print y x = []; y = x; x.append(10); print y will print [10] . x = []; y = x; x.append(10); print y将打印[10] The empty list was created.空列表已创建。 Both "x" and "y" point to the same list. “x”和“y”都指向同一个列表。 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). append方法改变(更新)列表对象(如向数据库中添加记录),结果对“x”和“y”都可见(就像数据库更新对该数据库的每个连接都是可见的)。

Hope that clarifies the issue for you.希望能为您澄清问题。

Technically, Python always uses pass by reference values .从技术上讲, Python 总是使用通过引用值传递 I am going to repeat my other answer to support my statement.我将重复我的其他答案以支持我的陈述。

Python always uses pass-by-reference values. Python 总是使用传递引用值。 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:这是证明 Python 使用按引用传递的示例:

传递参数的图解示例

If the argument was passed by value, the outer lst could not be modified.如果参数是按值传递的,则无法修改外部lst 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).您可以使用id()内置函数来了解引用值是什么(即目标对象的地址)。

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.在 Python 中,变量是绑定到引用变量的名称(内部捕获为字符串),该变量保存目标对象的引用值。 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.参考值隐藏在 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:我通常使用的一个简单技巧是将其包装在一个列表中:

def Change(self, var):
    var[0] = 'Changed'

variable = ['Original']
self.Change(variable)      
print variable[0]

(Yeah I know this can be inconvenient, but sometimes it is simple enough to do this.) (是的,我知道这可能很不方便,但有时这样做很简单。)

(edit - Blair has updated his enormously popular answer so that it is now accurate) (编辑 - 布莱尔更新了他广受欢迎的答案,现在它是准确的)

I think it is important to note that the current post with the most votes (by Blair Conrad), while being correct with respect to its result, is misleading and is borderline incorrect based on its definitions.我认为重要的是要注意当前投票最多的帖子(由布莱尔康拉德撰写),虽然就其结果而言是正确的,但它具有误导性,并且根据其定义是不正确的。 While there are many languages (like C) that allow the user to either pass by reference or pass by value, Python is not one of them.虽然有许多语言(如 C)允许用户通过引用传递或按值传递,但 Python 不是其中之一。

David Cournapeau's answer points to the real answer and explains why the behavior in Blair Conrad's post seems to be correct while the definitions are not. David Cournapeau 的回答指向了真正的答案,并解释了为什么 Blair Conrad 的帖子中的行为似乎是正确的,而定义却不是。

To the extent that Python is pass by value, all languages are pass by value since some piece of data (be it a "value" or a "reference") must be sent.在 Python 是按值传递的范围内,所有语言都是按值传递的,因为必须发送一些数据(无论是“值”还是“引用”)。 However, that does not mean that Python is pass by value in the sense that a C programmer would think of it.但是,这并不意味着 Python 在 C 程序员所认为的意义上是按值传递的。

If you want the behavior, Blair Conrad's answer is fine.如果你想要这种行为,布莱尔康拉德的回答很好。 But if you want to know the nuts and bolts of why Python is neither pass by value or pass by reference, read David Cournapeau's answer.但是,如果您想了解 Python 既不是按值传递也不是按引用传递的具体细节,请阅读 David Cournapeau 的回答。

You got some really good answers here.你在这里得到了一些非常好的答案。

x = [ 2, 4, 4, 5, 5 ]
print x  # 2, 4, 4, 5, 5

def go( li ) :
  li = [ 5, 6, 7, 8 ]  # re-assigning what li POINTS TO, does not
  # change the value of the ORIGINAL variable x

go( x ) 
print x  # 2, 4, 4, 5, 5  [ STILL! ]


raw_input( 'press any key to continue' )

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: Python 的传递赋值方案与 C++ 的引用参数选项并不完全相同,但实际上它与 C 语言(和其他语言)的参数传递模型非常相似:

  • Immutable arguments are effectively passed “ by value .”不可变参数有效地“按值”传递。 Objects such as integers and strings are passed by object reference instead of by copying, but because you can't change immutable objects in place anyhow, the effect is much like making a copy.整数和字符串等对象是通过对象引用而不是通过复制来传递的,但是由于您无论如何都无法更改不可变对象,因此效果很像复制。
  • Mutable arguments are effectively passed “ by pointer .”可变参数有效地“通过指针”传递。 Objects such as lists 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.列表和字典等对象也通过对象引用传递,这类似于 C 将数组作为指针传递的方式——可变对象可以在函数中就地更改,就像 C 数组一样。

In this case the variable titled var in the method Change is assigned a reference to self.variable , and you immediately assign a string to var .在这种情况下,方法Change中名为var的变量被分配了对self.variable的引用,并且您立即将字符串分配给var It's no longer pointing to self.variable .它不再指向self.variable The following code snippet shows what would happen if you modify the data structure pointed to by var and self.variable , in this case a list:以下代码片段显示了如果修改varself.variable指向的数据结构会发生什么,在本例中是一个列表:

>>> class PassByReference:
...     def __init__(self):
...         self.variable = ['Original']
...         self.change(self.variable)
...         print self.variable
...         
...     def change(self, var):
...         var.append('Changed')
... 
>>> q = PassByReference()
['Original', 'Changed']
>>> 

I'm sure someone else could clarify this further.我相信其他人可以进一步澄清这一点。

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 http://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

example:例子:

>>> def x(y):
...     global z
...     z = y
...

>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'z' is not defined

>>> x(2)
>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
2

A lot of insights in answers here, but i think an additional point is not clearly mentioned here explicitly.这里有很多关于答案的见解,但我认为这里没有明确提到另外一点。 Quoting from python documentation https://docs.python.org/2/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python引用 python 文档https://docs.python.org/2/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

"In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a new value anywhere within the function's body, it's assumed to be a local. If a variable is ever assigned a new value inside the function, the variable is implicitly local, and you need to explicitly declare it as 'global'. Though a bit surprising at first, a moment's consideration explains this. On one hand, requiring global for assigned variables provides a bar against unintended side-effects. On the other hand, if global was required for all global references, you'd be using global all the time. You'd have to declare as global every reference to a built-in function or to a component of an imported module. This clutter would defeat the usefulness of the global declaration for identifying side-effects." “在 Python 中,仅在函数内部引用的变量是隐式全局的。如果在函数体内的任何位置为变量分配了新值,则假定它是局部变量。如果在函数内部为变量分配了新值,该变量是隐式本地的,您需要将其显式声明为“全局”。虽然一开始有点令人惊讶,但考虑一下就可以解释这一点。一方面,要求为分配的变量全局提供了一个防止意外副作用的障碍。在另一方面,如果所有全局引用都需要全局,那么您将一直使用全局。您必须将每个对内置函数或导入模块组件的引用声明为全局。这种混乱将破坏全球宣言识别副作用的有用性。”

Even when passing a mutable object to a function this still applies.即使将可变对象传递给函数,这仍然适用。 And to me clearly explains the reason for the difference in behavior between assigning to the object and operating on the object in the function.对我来说,清楚地解释了分配给对象和在函数中对对象进行操作之间行为差异的原因。

def test(l):
    print "Received", l , id(l)
    l = [0, 0, 0]
    print "Changed to", l, id(l)  # New local object created, breaking link to global l

l= [1,2,3]
print "Original", l, id(l)
test(l)
print "After", l, id(l)

gives:给出:

Original [1, 2, 3] 4454645632
Received [1, 2, 3] 4454645632
Changed to [0, 0, 0] 4474591928
After [1, 2, 3] 4454645632

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.因此,对未声明为 global 的全局变量的赋值会创建一个新的局部对象并断开与原始对象的链接。

Here is the simple (I hope) explanation of the concept pass by object used in Python.这是 Python 中使用pass by object概念的简单(我希望)解释。
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.每当您将对象传递给函数时,传递的是对象本身(Python 中的对象实际上是您在其他编程语言中所称的值)而不是对该对象的引用。 In other words, when you call:换句话说,当你打电话时:

def change_me(list):
   list = [1, 2, 3]

my_list = [0, 1]
change_me(my_list)

The actual object - [0, 1] (which would be called a value in other programming languages) is being passed.实际对象 - [0, 1](在其他编程语言中称为值)正在传递。 So in fact the function change_me will try to do something like:所以实际上函数change_me会尝试做类似的事情:

[0, 1] = [1, 2, 3]

which obviously will not change the object passed to the function.这显然不会改变传递给函数的对象。 If the function looked like this:如果函数看起来像这样:

def change_me(list):
   list.append(2)

Then the call would result in:然后调用将导致:

[0, 1].append(2)

which obviously will change the object.这显然会改变对象。 This answer explains it well.这个答案很好地解释了它。

Aside from all the great explanations on how this stuff works in Python, I don't see a simple suggestion for the problem.除了关于这些东西如何在 Python 中工作的所有很好的解释之外,我没有看到针对该问题的简单建议。 As you seem to do create objects and instances, the pythonic way of handling instance variables and changing them is the following:正如您似乎确实创建了对象和实例,处理实例变量和更改它们的pythonic方法如下:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.Change()
        print self.variable

    def Change(self):
        self.variable = 'Changed'

In instance methods, you normally refer to self to access instance attributes.在实例方法中,您通常引用self来访问实例属性。 It is normal to set instance attributes in __init__ and read or change them in instance methods.__init__中设置实例属性并在实例方法中读取或更改它们是正常的。 That is also why you pass self als the first argument to def Change .这也是为什么您将self作为第一个参数传递给def Change的原因。

Another solution would be to create a static method like this:另一种解决方案是创建一个像这样的静态方法:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.variable = PassByReference.Change(self.variable)
        print self.variable

    @staticmethod
    def Change(var):
        var = 'Changed'
        return var

I used the following method to quickly convert a couple of Fortran codes to Python.我使用以下方法快速将几个 Fortran 代码转换为 Python。 True, it's not pass by reference as the original question was posed, but is a simple work around in some cases.诚然,它不是通过引用作为原始问题提出的,但在某些情况下是一个简单的解决方法。

a=0
b=0
c=0
def myfunc(a,b,c):
    a=1
    b=2
    c=3
    return a,b,c

a,b,c = myfunc(a,b,c)
print a,b,c

There is a little trick to pass an object by reference, even though the language doesn't make it possible.通过引用传递对象有一个小技巧,即使语言无法实现。 It works in Java too, it's the list with one item.它也适用于 Java,它是一个包含一项的列表。 ;-) ;-)

class PassByReference:
    def __init__(self, name):
        self.name = name

def changeRef(ref):
    ref[0] = PassByReference('Michael')

obj = PassByReference('Peter')
print obj.name

p = [obj] # A pointer to obj! ;-)
changeRef(p)

print p[0].name # p->name

It's an ugly hack, but it works.这是一个丑陋的黑客,但它有效。 ;-P ;-P

given the way python handles values and references to them, the only way you can reference an arbitrary instance attribute is by name:鉴于 python 处理值和对它们的引用的方式,您可以引用任意实例属性的唯一方法是通过名称:

class PassByReferenceIsh:
    def __init__(self):
        self.variable = 'Original'
        self.change('variable')
        print self.variable

    def change(self, var):
        self.__dict__[var] = 'Changed'

in real code you would, of course, add error checking on the dict lookup.当然,在实际代码中,您会在 dict 查找中添加错误检查。

Since your example happens to be object-oriented, you could make the following change to achieve a similar result:由于您的示例恰好是面向对象的,因此您可以进行以下更改以实现类似的结果:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change('variable')
        print(self.variable)

    def change(self, var):
        setattr(self, var, 'Changed')

# o.variable will equal 'Changed'
o = PassByReference()
assert o.variable == 'Changed'

Since dictionaries are passed by reference, you can use a dict variable to store any referenced values inside it.由于字典是通过引用传递的,因此您可以使用 dict 变量在其中存储任何引用的值。

# returns the result of adding numbers `a` and `b`
def AddNumbers(a, b, ref): # using a dict for reference
    result = a + b
    ref['multi'] = a * b # reference the multi. ref['multi'] is number
    ref['msg'] = "The result: " + str(result) + " was nice!"
    return result

number1 = 5
number2 = 10
ref = {} # init a dict like that so it can save all the referenced values. this is because all dictionaries are passed by reference, while strings and numbers do not.

sum = AddNumbers(number1, number2, ref)
print("sum: ", sum)             # the returned value
print("multi: ", ref['multi'])  # a referenced value
print("msg: ", ref['msg'])      # a referenced value

Since it seems to be nowhere mentioned an approach to simulate references as known from eg C++ is to use an "update" function and pass that instead of the actual variable (or rather, "name"):由于似乎没有提到模拟引用的方法,例如 C++ 中已知的方法是使用“更新”函数并传递它而不是实际变量(或者更确切地说,“名称”):

def need_to_modify(update):
    update(42) # set new value 42
    # other code

def call_it():
    value = 21
    def update_value(new_value):
        nonlocal value
        value = new_value
    need_to_modify(update_value)
    print(value) # prints 42

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.显然上面不允许读取值,只能更新它。

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.虽然通过引用传递并不适合 python 并且应该很少使用,但有一些变通方法实际上可以将当前分配给局部变量的对象或什至从被调用函数内部重新分配局部变量。

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) or nonlocal (for local variables in a function) in a wrapper function.一种方法是在包装函数中使用global (用于全局变量)或非nonlocal (用于函数中的局部变量)。

def change(wrapper):
    wrapper(7)

x = 5
def setter(val):
    global x
    x = val
print(x)

The same idea works for reading and del eting a variable.同样的想法适用于读取和del变量。

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.对于只是阅读,甚至还有一种更短的方法来使用lambda: x ,它返回一个可调用的,当被调用时返回 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:传递 3 个包装器来访问变量有点笨拙,因此可以将它们包装到具有代理属性的类中:

class ByRef:
    def __init__(self, r, w, d):
        self._read = r
        self._write = w
        self._delete = d
    def set(self, val):
        self._write(val)
    def get(self):
        return self._read()
    def remove(self):
        self._delete()
    wrapped = property(get, set, remove)

# left as an exercise for the reader: define set, get, remove as local functions using global / nonlocal
r = ByRef(get, set, remove)
r.wrapped = 15

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: Python 的“反射”支持使得获得能够在给定范围内重新分配名称/变量而无需在该范围内显式定义函数的对象成为可能:

class ByRef:
    def __init__(self, locs, name):
        self._locs = locs
        self._name = name
    def set(self, val):
        self._locs[self._name] = val
    def get(self):
        return self._locs[self._name]
    def remove(self):
        del self._locs[self._name]
    wrapped = property(get, set, remove)

def change(x):
    x.wrapped = 7

def test_me():
    x = 6
    print(x)
    change(ByRef(locals(), "x"))
    print(x)

Here the ByRef class wraps a dictionary access.这里的ByRef类包装了一个字典访问。 So attribute access to wrapped is translated to a item access in the passed dictionary.因此,对wrapped的属性访问被转换为传递字典中的项目访问。 By passing the result of the builtin locals and the name of a local variable this ends up accessing a local variable.通过传递内置locals变量的结果和局部变量的名称,最终可以访问局部变量。 The python documentation as of 3.5 advises that changing the dictionary might not work but it seems to work for me.从 3.5 开始的 python 文档建议更改字典可能不起作用,但它似乎对我有用。

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.请参阅示例。

class RefsObj(object):
    "A class which helps to create references to variables."
    pass

...

# an example of usage
def change_ref_var(ref_obj):
    ref_obj.val = 24

ref_obj = RefsObj()
ref_obj.val = 1
print(ref_obj.val) # or print ref_obj.val for python2
change_ref_var(ref_obj)
print(ref_obj.val)

Pass-By-Reference in Python is quite different from the concept of pass by reference in C++/Java. Python 中的引用传递与 C++/Java 中的引用传递概念完全不同。

  • Java&C#: primitive types(include string)pass by value(copy), Reference type is passed by reference(address copy) so all changes made in the parameter in the called function are visible to the caller. Java&C#:原始类型(包括字符串)按值传递(副本),引用类型按引用传递(地址副本),因此调用函数中对参数所做的所有更改对调用者都是可见的。
  • C++: Both pass-by-reference or pass-by-value are allowed. C++:允许按引用传递或按值传递。 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.如果参数是通过引用传递的,您可以根据参数是否作为 const 传递来修改或不修改它。 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.但是,无论是否为 const,参数都维护对对象的引用,并且不能将引用分配为指向被调用函数内的不同对象。
  • Python: Python is “pass-by-object-reference”, of which it is often said: “Object references are passed by value.”[Read here] 1 . Python: Python 是“传递对象引用”,也就是常说的:“对象引用是按值传递的。”[阅读这里] 1 . 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.与 C++ 一样,参数可以在函数中修改或不修改 - 这取决于传递的对象类型。 eg;例如; 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 re-assigning/re-initializing the mutable variable is that updated value gets reflected back in the called function whereas the reinitialized value does not.更新或重新分配/重新初始化可变变量之间的一个关键区别是更新的值会反映在被调用的函数中,而重新初始化的值不会。 Scope of any assignment of new object to a mutable variable is local to the function in the python.将新对象分配给可变变量的任何范围对于 python 中的函数都是本地的。 Examples provided by @blair-conrad are great to understand this. @blair-conrad 提供的示例非常有助于理解这一点。

I am new to Python, started yesterday (though I have been programming for 45 years).我是 Python 新手,从昨天开始(尽管我已经编程了 45 年)。

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.如果它只是一个输出参数,我现在不会挂断检查引用/值在 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.经验丰富的 Python 程序员当然已经知道我使用的解决方案,但它对我来说是新的。

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.从这里的答案中,我可以很快看到 Python 在这方面的工作方式有点像 Javascript,如果你想要参考功能,你需要使用变通方法。

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:但是后来我在 Python 中发现了一些我认为我以前在其他语言中没有见过的简洁的东西,即你可以以简单的逗号分隔方式从函数返回多个值,如下所示:

def somefunction(p):
    a=p+1
    b=p+2
    c=-p
    return a, b, c

and that you can handle that on the calling side similarly, like this并且您可以类似地在调用方处理它,就像这样

x, y, z = somefunction(w)

That was good enough for me and I was satisfied.这对我来说已经足够好了,我很满意。 No 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.在其他语言中,您当然也可以返回许多值,但通常在对象的 from 中,您需要相应地调整调用方。

The Python way of doing it was nice and simple. Python 的做法很简单。

If you want to mimic by reference even more, you could do as follows:如果您想通过引用来模仿更多,您可以执行以下操作:

def somefunction(a, b, c):
    a = a * 2
    b = b + a
    c = a * b * c
    return a, b, c

x = 3
y = 5
z = 10
print(F"Before : {x}, {y}, {z}")

x, y, z = somefunction(x, y, z)

print(F"After  : {x}, {y}, {z}")

which gives this result这给出了这个结果

Before : 3, 5, 10  
After  : 6, 11, 660

alternatively you could use ctypes witch would look something like this或者你可以使用 ctypes 女巫看起来像这样

import ctypes

def f(a):
    a.value=2398 ## resign the value in a function

a = ctypes.c_int(0)
print("pre f", a)
f(a)
print("post f", a)

as a is ac int and not a python integer and apperently passed by reference.因为 a 是 ac int 而不是 python 整数,并且显然是通过引用传递的。 however you have to be carefull as strange things could happen and is therefor not advised但是你必须小心,因为可能会发生奇怪的事情,因此不建议

Most likely not the most reliable method but this works, keep in mind that you are overloading the built-in str function which is typically something you don't want to do:很可能不是最可靠的方法,但这是可行的,请记住,您正在重载内置的 str 函数,这通常是您不想做的事情:

import builtins

class sstr(str):
    def __str__(self):
        if hasattr(self, 'changed'):
            return self.changed

        return self

    def change(self, value):
        self.changed = value

builtins.str = sstr

def change_the_value(val):
    val.change('After')

val = str('Before')
print (val)
change_the_value(val)
print (val)

What about dataclasses ?数据类呢? Also, it allows you to apply type restriction (aka "type hint").此外,它还允许您应用类型限制(又名“类型提示”)。

from dataclasses import dataclass

@dataclass
class Holder:
    obj: your_type # Need any type? Use "obj: object" then.

def foo(ref: Holder):
    ref.obj = do_something()

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 explicit context class though.您可以设计显式上下文类。 When prototyping I prefer dataclasses, just because it's easy to serialize them back and forth.在进行原型设计时,我更喜欢数据类,只是因为很容易来回序列化它们。

Cheers!干杯!

  1. Python assigns a unique identifier to each object and this identifier can be found by using Python's built-in id() function. Python 为每个对象分配一个唯一标识符,并且可以使用 Python 的内置id()函数找到该标识符。 It is ready to verify that actual and formal arguments in a function call have the same id value, which indicates that the dummy argument and actual argument refer to the same object.可以验证函数调用中的实际参数和形式参数是否具有相同的 id 值,这表明虚拟参数和实际参数引用的是同一个对象。

  2. Note that the actual argument and the corresponding dummy argument are two names referring to the same object.请注意,实际参数和相应的虚拟参数是指同一个对象的两个名称。 If you re-bind a dummy argument to a new value/object in the function scope, this does not effect the fact that the actual argument still points to the original object because actual argument and dummy argument are two names.如果您将虚拟参数重新绑定到函数范围内的新值/对象,这不会影响实际参数仍然指向原始对象的事实,因为实际参数和虚拟参数是两个名称。

  3. The above two facts can be summarized as “arguments are passed by assignment”.上述两个事实可以概括为“参数通过赋值传递”。 ie, IE,

dummy_argument = actual_argument

If you re-bind dummy_argument to a new object in the function body, the actual_argument still refers to the original object.如果将dummy_argument重新绑定到函数体中的新对象, actual_argument仍然引用原始对象。 If you use dummy_argument[0] = some_thing , then this will also modify actual_argument[0] .如果您使用dummy_argument[0] = some_thing ,那么这也会修改actual_argument[0] Therefore the effect of “pass by reference” can be achieved by modifying the components/attributes of the object reference passed in. Of course, this requires that the object passed is a mutable object.因此通过修改传入的对象引用的组件/属性可以达到“通过引用传递”的效果。当然,这要求传递的对象是可变对象。

  1. To make comparison with other languages, you can say Python passes arguments by value in the same way as C does, where when you pass "by reference" you are actually passing by value the reference (ie, the pointer)为了与其他语言进行比较,您可以说 Python 以与 C 相同的方式按值传递参数,当您通过“按引用”传递时,实际上是按值传递引用(即指针)
def i_my_wstring_length(wstring_input:str = "", i_length:int = 0) -> int:
    i_length[0] = len(wstring_input)
    return 0

wstring_test  = "Test message with 32 characters."
i_length_test = [0]
i_my_wstring_length(wstring_test, i_length_test)
print("The string:\n\"{}\"\ncontains {} character(s).".format(wstring_test, *i_length_test))
input("\nPress ENTER key to continue . . . ")

Any variable in Python stores a value . Python 中的任何变量都存储一个值

Assigning a variable to another, included a function argument, creates a copy of that value.将一个变量分配给另一个变量,包括一个函数参数,会创建该值的副本

For a scalar variable, that value is just the value to retrieve (a number, string, etc).对于标量变量,该值只是要检索的值(数字、字符串等)。

For a list , that value is an address that references the location another value/s .对于list ,该 value 是引用另一个 value/s位置的地址

There is also the global keyword , it extends the scope of a variable to the function where is applied.还有global 关键字,它将变量的范围扩展到应用的函数。

Scalar example标量示例

标量示例

List example列表示例

列表示例

Global example全局示例

在此处输入图像描述

References参考

There is a python course that explains these concepts, and have also a sandbox to test the code, here are the relevant sections:有一个 Python 课程解释了这些概念,还有一个沙箱来测试代码,以下是相关部分:

This might be an elegant object oriented solution without this functionality in Python.这可能是一个优雅的面向对象的解决方案,在 Python 中没有此功能。 An even more elegant solution would be to have any class you make subclass from this.一个更优雅的解决方案是让任何你从中创建子类的类。 Or you could name it "MasterClass".或者您可以将其命名为“MasterClass”。 But instead of having a single variable and a single boolean, make them a collection of some kind.但不是只有一个变量和一个布尔值,而是让它们成为某种集合。 I fixed the naming of your instance variables to comply with PEP 8.我修复了实例变量的命名以符合 PEP 8。

class PassByReference:
    def __init__(self, variable, pass_by_reference=True):
        self._variable_original = 'Original'
        self._variable = variable
        self._pass_by_reference = pass_by_reference # False => pass_by_value
        self.change(self.variable)
        print(self)

    def __str__(self):
        print(self.get_variable())

    def get_variable(self):
        if pass_by_reference == True:
            return self._variable
        else:
            return self._variable_original

    def set_variable(self, something):
        self._variable = something

    def change(self, var):
        self.set_variable(var)

def caller_method():

    pbr = PassByReference(variable='Changed') # this will print 'Changed'
    variable = pbr.get_variable() # this will assign value 'Changed'

    pbr2 = PassByReference(variable='Changed', pass_by_reference=False) # this will print 'Original'
    variable2 = pbr2.get_variable() # this will assign value 'Original'
    

I solved a similar requirement as follows:我解决了一个类似的要求,如下所示:

To implement a member function that changes a variable, dont pass the variable itself, but pass a functools.partial that contains setattr referring to the variable.要实现更改变量的成员函数,请不要传递变量本身,而是传递包含引用变量的setattrfunctools.partial Calling the functools.partial inside change() will execute settatr and change the actual referenced variable.change()中调用functools.partial将执行settatr并更改实际引用的变量。

Note that setattr needs the name of the variable as string.请注意, setattr需要将变量的名称作为字符串。

class PassByReference(object):
    def __init__(self):
        self.variable = "Original"
        print(self.variable)        
        self.change(partial(setattr,self,"variable"))
        print(self.variable)

    def change(self, setter):
        setter("Changed")

Most of the time, the variable to be passed by reference is a class member.大多数时候,通过引用传递的变量是类成员。 The solution I suggest is to use a decorator to add both a field that is mutable and corresponding property.我建议的解决方案是使用装饰器来添加可变字段和相应属性。 The field is a class wrapper around the variable.该字段是围绕变量的类包装器。

The @refproperty adds both self._myvar (mutable) and self.myvar property. @refproperty添加了self._myvar (可变)和self.myvar属性。

@refproperty('myvar')
class T():
    pass

def f(x):
   x.value=6

y=T()
y.myvar=3
f(y._myvar)
print(y.myvar) 

It will print 6.它将打印 6。

Compare this to:将此与以下内容进行比较:

class X:
   pass

x=X()
x.myvar=4

def f(y):
    y=6

f(x.myvar)
print(x.myvar) 

In this case, it won't work.在这种情况下,它不起作用。 It will print 4.它将打印 4。

The code is the following:代码如下:

def refproperty(var,value=None):
    def getp(self):
        return getattr(self,'_'+var).get(self)

    def setp(self,v):
        return getattr(self,'_'+var).set(self,v)

    def decorator(klass):
        orginit=klass.__init__
        setattr(klass,var,property(getp,setp))

        def newinit(self,*args,**kw):
            rv=RefVar(value)
            setattr(self,'_'+var,rv)
            orginit(self,*args,**kw)

        klass.__init__=newinit
        return klass
    return decorator

class RefVar(object):
    def __init__(self, value=None):
        self.value = value
    def get(self,*args):
        return self.value
    def set(self,main, value):
        self.value = value

Simple Answer:简单的答案:

In python like c++, when you create an object instance and pass it as a parameter, no copies of the instance itself get made, so you are referencing the same instance from outside and inside the function and are able to modify the component datums of the same object instance,hence changes are visible to the outside.在像 c++ 这样的 python 中,当您创建一个对象实例并将其作为参数传递时,不会生成实例本身的副本,因此您可以从函数外部和内部引用同一个实例,并且能够修改组件的基准相同的对象实例,因此外部可见更改。

For basic types, python and c++ also behave the same to each other, in that copies of the instances are now made, so the outside sees/modifies a different instance than the inside of the function.对于基本类型,python 和 c++ 的行为也彼此相同,因为现在制作了实例的副本,因此外部看到/修改了与函数内部不同的实例。 Hence changes from the inside are not visible on the outside.因此,内部的变化在外部是不可见的。

Here comes the real difference between python and c++:这是python和c ++之间的真正区别:

c++ has the concept of address pointers, and c++ allows you to pass pointers instead, which bypasses the copying of basic types, so that the inside of the function can affect the same instances as those outside, so that the changes are also visible to the outside. c++有地址指针的概念,c++允许你改为传递指针,绕过了基本类型的复制,这样函数内部就可以影响到和外部一样的实例,这样变化对函数也是可见的外部。 This has no equivalent in python, so is not possible without workarounds (such as creating wrapper types).这在 python 中没有等价物,因此如果没有变通方法(例如创建包装器类型)是不可能的。

Such pointers can be useful in python, but it's not as necessary as it is in c++, because in c++, you can only return a single entity, whereas in python you can return multiple values separated by commas (ie a tuple).这样的指针在 python 中可能很有用,但它不像在 c++ 中那样必要,因为在 c++ 中,您只能返回单个实体,而在 python 中,您可以返回由逗号分隔的多个值(即元组)。 So in python, if you have variables a,b, and c, and want a function to modify them persistently (relative to the outside), you would do this:所以在 python 中,如果你有变量 a、b 和 c,并且想要一个函数来持久地修改它们(相对于外部),你可以这样做:

a=4
b=3
c=8

a,b,c=somefunc(a,b,c)
# a,b,c now have different values here

Such syntax is not easily possible in c++, thus in c++ you would do this instead:这样的语法在 c++ 中不容易实现,因此在 c++ 中你可以这样做:

int a=4
int b=3
int c=8
somefunc(&a,&b,&c)
// a,b,c now have different values here

I share another fun way for people to comprehend this topic over a handy tool - VISUALIZE PYTHON CODE EXECUTION based on the example of passing a mutable list from @Mark Ransom我分享了另一种有趣的方式让人们通过一个方便的工具来理解这个主题 - 基于传递来自@Mark Ransom 的可变列表的示例,可视化 PYTHON 代码执行

Just play it around, and then you will figure it out.随便玩玩,然后你就知道了。

  1. Passing a String传递一个字符串

在此处输入图像描述

  1. Passing a List传递列表

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM