Я вижу три фундаментальные концепции Python, которые могут пролить свет на вопрос:
1) Во-первых, присвоение из изменяемого объекта, как в
self.foo = arg1
, похоже на копированиеуказатель (а не значение, на которое указывает): self.foo
и arg1
- это один и тот же объект.Вот почему следующая строка
self.foo.age = 23
изменяет arg1
(то есть Person1
). Таким образом, переменные - это разные «имена» или «метки», которые могут указывать на уникальный объект (здесь объект person
).Это объясняет, почему baz(Person1)
изменяет Person1.age
и bar1.foo.age
на 27, поскольку Person1
и bar1.foo
- это просто два имени для одного и того же person
объекта (Person1 is bar1.foo
возвращает True
, в Python).
2) Вторым важным понятием является назначение.В
def teh(arg1):
arg1 = [3,2,1]
переменная arg1
является локальной, поэтому код
meh = [1,2,3]
teh(meh)
сначала делает arg1 = meh
, что означает, что arg1
является дополнительным (локальным) именем длясписок meh
;но делать arg1 = [3, 2, 1]
- все равно что сказать: «Я передумал: с этого момента arg1
будет именем нового списка [3, 2, 1]».Здесь важно помнить, что назначения, несмотря на то, что они обозначены знаком «равно», являются асимметричными : они дают (изменяемому) объекту справа и справа дополнительное имя,дано в левой части (поэтому вы не можете сделать [3, 2, 1] = arg1
, поскольку в левой части должно быть имя [или имена]).Таким образом, arg1 = meh; arg1 = [3, 2, 1]
не может измениться meh
.
3) Последний пункт связан с названием вопроса: «передача по значению» и «передача по ссылке» не являются понятиями, которые актуальны в Python.Соответствующими понятиями являются « изменяемый объект » и « неизменяемый объект ».Списки изменчивы, а числа нет, что объясняет то, что вы наблюдаете.Кроме того, ваши объекты Person1
и bar1
являются изменяемыми (поэтому вы можете изменить возраст человека).Вы можете найти больше информации об этих понятиях в текстовом руководстве и видеоуроке .В Википедии также есть некоторая (более техническая) информация .Пример иллюстрирует различие в поведении между изменяемым и неизменным:
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
.
Три вышеприведенных понятия (переменные как имена [для изменяемых объектов], асимметричное назначение и изменчивость / неизменность) объясняют многие из Pythonповедения.