Как передать переменную по ссылке?

Функция псевдонима предназначена для простых псевдонимов имен и не допускает аргументов. Вам нужна функция, например :

function scheme {
    & "C:\Program Files (x86)\MIT-GNU Scheme\bin\mit-scheme.exe" --library "C:\Program Files (x86)\MIT-GNU Scheme\lib"
}
2392
задан Taryn 22 March 2017 в 16:16
поделиться

6 ответов

Аргументы передаются путем присваивания . Обоснование этого двоякое:

  1. переданный параметр на самом деле является ссылкой на объект (но ссылка передается по значению)
  2. некоторые типы данных являются изменяемыми, а другие нет.

Итак:

  • Если вы передадите изменяемый объект в метод, метод получит ссылку на тот же объект, и вы сможете изменить его к своему удовольствию, но если вы повторно привяжете ссылку в метода, внешняя область ничего не будет знать о нем, и после того, как вы закончите, внешняя ссылка все еще будет указывать на исходный объект.

  • Если вы передадите методу неизменяемый объект, вы все равно не сможете повторно привязать внешнюю ссылку и даже не сможете изменить объект.

Чтобы сделать это еще более понятным, позвольте ' Есть несколько примеров.

Список - изменяемый тип

Давайте попробуем изменить список, переданный методу:

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)

Вывод:

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

Поскольку переданный параметр является ссылкой на external_list , а не копию этого, мы можем использовать методы изменяющегося списка, чтобы изменить его и отразить изменения во внешней области.

Теперь давайте посмотрим, что происходит, когда мы пытаемся изменить ссылку, переданную в качестве параметра:

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)

Вывод:

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']

Поскольку параметр the_list был передан по значению, присвоение ему нового списка не повлияло на то, что код вне метода мог видеть. the_list был копией ссылки outer_list , и у нас было the_list , указывающее на новый список, но не было возможности изменить где external_list указал.

String - неизменяемый тип

Он неизменяемый, поэтому мы ничего не можем сделать, чтобы изменить содержимое строки

Теперь давайте попробуем изменить ссылку.

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)

Вывод:

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

Опять же, поскольку Параметр the_string был передан по значению, присвоение ему новой строки не повлияло на то, что код вне метода мог видеть. the_string была копией ссылки outer_string , и у нас была the_string , указывающая на новую строку, но не было возможности изменить где external_string указал.

Надеюсь, это немного проясняет ситуацию.

РЕДАКТИРОВАТЬ: Было отмечено, что это не отвечает на вопрос, который первоначально задал @David: «Могу ли я что-то сделать с передать переменную по фактической ссылке? ". Давайте работать над этим.

Как это обойти?

Как показывает ответ @Andrea, вы можете вернуть новое значение. Это не меняет способа передачи данных, но позволяет получить обратно нужную информацию:

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)

Если вы действительно хотите избежать использования возвращаемого значения, вы можете создать класс для хранения вашего значения и его передачи. в функцию или используйте существующий класс, например список:

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])

Хотя это кажется немного громоздким.

2661
ответ дан 22 November 2019 в 19:51
поделиться

У вас есть несколько действительно хороших ответов.

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' )
23
ответ дан 22 November 2019 в 19:51
поделиться

Подумайте о том, что передается по назначению , а не по ссылке / по значению. Таким образом, всегда ясно, что происходит, если вы понимаете, что происходит во время обычного присваивания.

Итак, при передаче списка в функцию / метод список присваивается имени параметра. Добавление к списку приведет к изменению списка. Переназначение списка внутри функция не изменит исходный список, поскольку:

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

Поскольку неизменяемые типы не могут быть изменены, они кажутся как передаваемые по значению - передача int в функция означает присвоение int параметру функции. Вы можете только переназначить это значение, но это не изменит исходное значение переменных.

162
ответ дан 22 November 2019 в 19:51
поделиться

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. It's no longer pointing to 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:

>>> 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.

18
ответ дан 22 November 2019 в 19:51
поделиться

Это не передача по значению или по ссылке - это вызов по объекту. См. Это Фредрик Лунд:

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

Вот важная цитата:

«... переменные [имена] равны , а не объектов; они не могут быть обозначены другими переменными или на них нельзя ссылаться ».

В вашем примере, когда вызывается метод Change - пространство имен создан для этого; и var становится именем в этом пространстве имен для строкового объекта 'Original' . Затем этот объект имеет имя в двух пространствах имен. Затем var = 'Changed' связывает var с новым строковым объектом, и, таким образом, пространство имен метода забывает о 'Original' . В заключение,

232
ответ дан 22 November 2019 в 19:51
поделиться

(edit - Blair обновил свой чрезвычайно популярный ответ, так что теперь он точен)

Я думаю, важно отметить, что текущий пост с наибольшим количеством голосов (автор Blair Conrad), хотя и является правильным в отношении результата, вводит в заблуждение и является погранично неправильным на основе своих определений. Хотя есть много языков (например, C), которые позволяют пользователю передавать по ссылке или по значению, Python не является одним из них.

Ответ Дэвида Курнапо указывает на реальный ответ и объясняет, почему поведение в посте Блэра Конрада кажется правильным, а определения - нет.

В той степени, в которой Python является передачей по значению, все языки являются передачей по значению, поскольку некоторая часть данных (будь то "значение" или "ссылка") должна быть отправлена. Однако это не означает, что Python - это передача по значению в том смысле, в котором об этом подумал бы программист на языке Си.

Если вам нужно поведение, то ответ Блэра Конрада вполне подойдет. Но если вы хотите узнать, почему Python не является ни передачей по значению, ни передачей по ссылке, прочитайте ответ Дэвида Курнапо.

37
ответ дан 22 November 2019 в 19:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: