Изучая Python, я прочитал это:
Аргументы не являются ни
“passed-by-reference“
ни“passed-by-value“
,
Они есть“passed-by-object-reference”
,
Я пытаюсь понять и сравнить это с точки зрения C ++.
Является ли поведение передачи аргументов в Python таким же, как std::reference_wrapper
с в С ++?
Сохраняется ли эта аналогия с точки зрения поведения и предполагаемых вариантов использования?
Краткий ответ: нет, std::reference_wrapper<T>
не делает этого, потому что различия между C ++ и Python (на практике) — это такие вопросы, как «что происходит в куче» и «какие типы неизменны».
В Python все идет по куче. Числа, строки и указатели являются неизменными. Вы не можете иметь указатели на переменные. Python передается по значению, как почти каждый современный язык.
В C ++ вы выбираете, что происходит в куче. Почти все может быть изменено. Вы можете иметь указатели на переменные, указатели на внутренние объекты и передавать большие структуры данных, копируя их. C ++ в основном передается по значению, как почти любой современный язык, за исключением того, что вы можете пометить некоторые параметры как переданные по ссылке.
Честно говоря, люди делают это сложнее, чем на самом деле. Проблема с простым произнесением «передача по значению» или «передача по ссылке» заключается в том, что наше интуитивное понимание «ценности» и «ссылки» не соответствует техническому способу их использования здесь.
Вот четкое доказательство того, что Python передается по значению:
def func(x):
x = [4, 5, 5]
def func2():
y = [1, 2, 3]
func(y)
print(y) # prints [1, 2, 3]
Запутанная часть состоит в том, что новичок будет думать, что [1, 2, 3]
это значение, но опытный пользователь Python поймет, что [1, 2, 3]
это содержимое объекта, а указатель к этому объекту затем передается (по значению) в функцию. Здесь начинающие спотыкаются:
def func(x):
x[:] = [4, 5, 6]
def func2():
y = [1, 2, 3]
func(y)
print(y) # prints [4, 5, 6]
Я думаю, что это явное доказательство того, что x
а также y
являются указателями на один и тот же объект. Мы знаем это x
не является ссылкой на y
, так как присвоение нового значения x
не влияет y
, В C это работает так же, но по какой-то причине люди менее запутаны.
void func(int *x) {
x[0] = 4; x[1] = 5; x[2] = 6;
}
void func2() {
int y[3] = {1, 2, 3};
func(y);
printf("%d, %d, %d\n", y[0], y[1], y[2]);
}
То же самое обсуждалось в сообществе Java с тем же выводом. В Java переменные с типом объекта содержат указатели. Эти указатели передаются по значению. Функции Java передаются по значению. Увидеть Черт возьми, Java это передача по значению! или же Является ли Java «передачей по ссылке» или «передачей по значению»?
«Передача по значению объекта» — ненужный термин для людей, которые не понимают, что такое указатели, и думают, что в Python нет указателей, потому что он называет их «ссылками». Java сделала нормальную вещь и фактически назвала их указателями в спецификации Java.
Другая запутанная часть о Python, так как объекты, такие как 6.28 или "Hello, World!"
являются неизменяемыми, вы не можете определить разницу между передачей содержимого объекта по значению и передачей указателя по значению. (И CPython — только одна реализация.)
std::reference_wrapper<T>
за?Единственное, что здесь происходит, это то, что в C ++ есть два типа указателей. Некоторые указатели называются «указателями», а некоторые называются «ссылками». Это одна и та же базовая концепция, выраженная по-разному. Цель std::reference_wrapper<T>
сделать что-то похожее на ссылку C ++, но может быть переназначено. Или, если хотите, что-то похожее на указатель C ++, но оно не может быть NULL. В конце концов, это все еще концептуально указатель, даже если вы называете его ссылкой. Или это все еще концептуально ссылка, даже если она не ведет себя точно так же, как T&
,
Как в Python или Java, где у вас есть указатели на объекты, даже если вы решили называть их ссылками.
Других решений пока нет …