问题描述
何时更改对象以及何时不使用Python出现问题.这是下面我做得不好的例子:
Having issues with when objects are changed and when they aren't in Python. Here is my poorly contrived example below:
class person:
age = 21
class bar:
def __init__(self, arg1):
self.foo = arg1
self.foo.age = 23
def baz(arg1):
arg1.age = 27
def teh(arg1):
arg1 = [3,2,1]
Person1 = person()
bar1 = bar(Person1)
print Person1.age
print bar1.foo.age
baz(Person1)
print Person1.age
print bar1.foo.age
meh = [1,2,3]
teh(meh)
print meh
输出为
23
23
27
27
[1, 2, 3]
因此,当我们声明Person1时,Person1.age为21.对此对象的引用将传递到bar的另一个类实例bar1的类构造函数.对此参考所做的任何更改都会更改Person1.
So when we declare Person1, Person1.age is 21. A reference to this object is passed to the class constructor of another class instance of bar, called bar1. Any changes made to this reference will change Person1.
当我们将Person1传递给普通函数时,情况也是如此,Person1.age现在等于27.
This is also the case when we pass Person1 to a normal function, the Person1.age now equals 27.
但是为什么对变量"meh"不起作用?当然,如果我们分配变量a = meh
并更改a = [6, 6, 6]
,那么meh也将被更改.我很困惑.有没有关于这一切如何运作的文献?
But why doesn't this work on the variable "meh"? Certainly, if we assign a variable a = meh
and change a = [6, 6, 6]
, then meh will also be changed. I'm confused. Is there any literature on how all this works?
推荐答案
我可以看到三个基本的Python概念,它们可以使您对问题有所了解:
I can see three fundamental Python concepts that can shine some light on the question:
1)首先,来自像这样的可变对象的分配
1) First, an assignment from a mutable object like in
self.foo = arg1
就像复制一个指针(而不是指向的值):self.foo
和arg1
是 same 对象.这就是为什么接下来的那行,
is like copying a pointer (and not the value pointed to): self.foo
and arg1
are the same object. That's why the line that follows,
self.foo.age = 23
修改arg1
(即Person1
). 变量因此是可以指向唯一对象的不同名称"或标签" (此处为person
对象).这解释了为什么baz(Person1)
将Person1.age
和 bar1.foo.age
修改为27,因为Person1
和bar1.foo
只是 same person
对象的两个名称. (在Python中,Person1 is bar1.foo
返回True
).
modifies arg1
(i.e. Person1
). Variables are thus different "names" or "labels" that can point to a unique object (here, a person
object). This explains why baz(Person1)
modifies Person1.age
and bar1.foo.age
to 27, since Person1
and bar1.foo
are just two names for the same person
object (Person1 is bar1.foo
returns True
, in Python).
2)第二个重要概念是赋值.在
2) The second important notion is that of assignments. In
def teh(arg1):
arg1 = [3,2,1]
变量arg1
是局部变量,因此代码
variable arg1
is local, so that the code
meh = [1,2,3]
teh(meh)
首先执行arg1 = meh
,这意味着arg1
是列表meh
的附加(本地)名称;但是执行arg1 = [3, 2, 1]
就像说我改变了主意:arg1
从现在开始将是 new 列表的名称,[3,2,1]".这里要记住的重要一点是,尽管赋值用等号"表示,但它们是不对称的:它们为右侧的(可变)对象赋予了另外一个名称,在左侧给出(这就是为什么您不能执行[3, 2, 1] = arg1
的原因,因为左侧必须是名称[或名称]).因此,arg1 = meh; arg1 = [3, 2, 1]
不能更改meh
.
first does arg1 = meh
, which means that arg1
is an additional (local) name for list meh
; but doing arg1 = [3, 2, 1]
is like saying "I changed my mind: arg1
will from now on be the name of a new list, [3, 2, 1]". The important thing to keep in mind here is that assignments, despite being denoted with an "equal" sign, are asymmetrical: they give to a (mutable) object on the right-and-side an additional name, given in the left-hand side (that's why you can't do [3, 2, 1] = arg1
, as the left-hand side must be a name [or names]). So, arg1 = meh; arg1 = [3, 2, 1]
cannot change meh
.
3)最后一点与问题标题有关:按值传递"和按引用传递"不是Python中相关的概念.相反,相关概念是"可变对象"和"不可变对象".列表是可变的,而数字不是可变的,这说明了您观察到的内容.另外,您的Person1
和bar1
对象是可变的(这就是为什么您可以更改此人的年龄).您可以在文本教程和.维基百科也有一些(更多技术性)信息.一个例子说明了可变和不可变之间的行为差异:
3) The last point is related to the question title: "passing by value" and "passing by reference" are not concepts that are relevant in Python. The relevant concepts are instead "mutable object" and "immutable object". Lists are mutable, while numbers are not, which explains what you observe. Also, your Person1
and bar1
objects are mutable (that's why you can change the person's age). You can find more information about these notions in a text tutorial and a video tutorial. Wikipedia also has some (more technical) information. An example illustrates the difference of behavior between mutable and immutable:
x = (4, 2)
y = x # This is equivalent to copying the value (4, 2), because tuples are immutable
y += (1, 2, 3) # This does not change x, because tuples are immutable; this does y = (4, 2) + (1, 2, 3)
x = [4, 2]
y = x # This is equivalent to copying a pointer to the [4, 2] list
y += [1, 2, 3] # This also changes x, because x and y are different names for the same (mutable) object
最后一行不等效于y = y + [1, 2, 3]
,因为这只会在变量y
中放置一个新的列表对象,而不是更改y
和x
都引用的列表
The last line is not equivalent to y = y + [1, 2, 3]
because this would only put a new list object in variable y
instead of changing the list referred to by both y
and x
.
以上三个概念(变量[用于可变对象的名称],不对称赋值和可变性/不可变性)解释了许多Python的行为.
The three concepts above (variables as names [for mutable objects], asymmetrical assignment, and mutability/immutability) explain many of Python's behaviors.
这篇关于难以理解在Python中传递值和引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!