var, переданный функции kwargs, не обновляется [duplicate]

awk Версия:

awk '/regexp/ { getline; print $0; }' filetosearch
38
задан Timothy Lawman 9 November 2012 в 01:43
поделиться

9 ответов

Вы не можете передать простой примитив по ссылке в Python, но вы можете делать такие вещи, как:

def foo(y):
  y[0] = y[0]**2

x = [5]
foo(x)
print x[0]  # prints 25

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

def foo(x, y):
   return x**2, y**2

a = 1
b = 2
a, b = foo(a, b)  # a == 2; b == 4

Когда вы возвращаете такие значения, они возвращаются как Кортеж, который, в свою очередь, распакован.

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

def clear_a(x):
  x = []

def clear_b(x):
  while x: x.pop()

z = [1,2,3]
clear_a(z) # z will not be changed
clear_b(z) # z will be emptied
44
ответ дан dave mankoff 21 August 2018 в 20:39
поделиться
  • 1
    Было бы полезно увидеть результаты программ. Например, 'print x [0]' return 25? (Да, но это должно быть показано.) – Ray Salemi 3 September 2017 в 17:13
  • 2
    почему не clear_a изменить z? – alexey 8 September 2017 в 03:37
  • 3
    @alexey clear_a получает ссылку на z и сохраняет эту ссылку в x. Затем он немедленно изменяет x на ссылку на другой массив. Оригинальный массив z забыт в области clear_a, но фактически не изменен. Он остается неизменным при возврате в глобальную область. Контрастируйте это с помощью clear_b, который ссылается на z, а затем работает непосредственно на нем, не создавая нового массива или иначе указывая x и что-то другое. – dave mankoff 8 September 2017 в 14:21
  • 4
    спасибо, Дэйв! Я попытался создать новый массив & quot; в clear_b, y = x, y: y.pop() и затем вызвал clear_b(z), z все еще освободился ... Поэтому нам нужно что-то вроде y = list(x), чтобы создать копию x (список (x), объясненный здесь здесь ) – alexey 11 September 2017 в 18:59

Надеемся, что следующее описание суммирует его хорошо:

Здесь есть две вещи - переменные и объекты.

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

Пример:

def changeval( myvar ):
   myvar = 20; 
   print "values inside the function: ", myvar
   return

myvar = 10;
changeval( myvar );
print "values outside the function: ", myvar

O / P:

values inside the function:  20 
values outside the function:  10
  1. Если вы передаете переменные, упакованные внутри изменяемого объекта, например список, то изменения, внесенные в объект, отражаются глобально до тех пор, пока объект не будет повторно назначен.

Пример :

def changelist( mylist ):
   mylist2=['a'];
   mylist.append(mylist2);
   print "values inside the function: ", mylist
   return

mylist = [1,2,3];
changelist( mylist );
print "values outside the function: ", mylist

O / P:

values inside the function:  [1, 2, 3, ['a']]
values outside the function:  [1, 2, 3, ['a']]
  1. Теперь рассмотрим случай, когда объект переназначается. В этом случае объект относится к новой ячейке памяти, которая является локальной для функции, в которой это происходит и, следовательно, не отражается глобально.

Пример:

def changelist( mylist ):
   mylist=['a'];
   print "values inside the function: ", mylist
   return

mylist = [1,2,3];
changelist( mylist );
print "values outside the function: ", mylist

O / P:

values inside the function:  ['a']
values outside the function:  [1, 2, 3]
14
ответ дан Abhijeet Kasurde 21 August 2018 в 20:39
поделиться
  • 1
    Это лучшее резюме! ^^^ ЛУЧШЕЕ РЕЗЮМЕ ЗДЕСЬ ^^^ все читают этот ответ! 1. передать простые переменные. 2. передать ссылку на объект, которая будет изменена. 3. передать ссылку на объект, которая переназначается в функции – gaoithe 25 October 2017 в 10:22
  • 2
    Этот ответ очень смущен. Python не передает разные значения по-разному: все аргументы функции в Python получают свои значения по назначению и ведут себя точно так же, как назначение ведет себя где-нибудь еще на языке. («Хотя этот способ может быть не очевидным сначала, если вы не голландский»). – Daniel Pryden 15 March 2018 в 18:06

Хорошо, я возьму на это удар. Python проходит по ссылке объекта, которая отличается от того, что вы обычно считаете «по ссылке» или «по значению». Возьмем этот пример:

def foo(x):
    print x

bar = 'some value'
foo(bar)

Итак, вы создаете строковый объект со значением «некоторое значение» и «привязываете» его к переменной с именем bar. В C это будет похоже на bar, являющимся указателем на «некоторое значение».

Когда вы вызываете foo(bar), вы не переходите в bar. Вы передаете значение bar: указатель на «некоторое значение». В этот момент есть два «указателя» на один и тот же строковый объект.

Теперь сравните это с:

def foo(x):
    x = 'another value'
    print x

bar = 'some value'
foo(bar)

Вот где разница. В строке:

x = 'another value'

вы фактически не изменяете содержимое x. На самом деле это даже невозможно. Вместо этого вы создаете новый строковый объект со значением «другое значение». Этот оператор присваивания? Он не говорит, что «перезаписывает вещь x указывает на новое значение». Он говорит «обновить x, чтобы вместо этого указать на новый объект». После этой строки есть два строковых объекта: «некоторое значение» (с указанием bar, указывающее на него) и «другое значение» (при этом x указывает на него).

Это не неуклюжие , Когда вы понимаете, как это работает, это красиво элегантная, эффективная система.

20
ответ дан Bob Boykin 21 August 2018 в 20:39
поделиться
  • 1
    Но что, если я хочу функцию изменить содержимое моей переменной? Я полагаю, что нет никакого способа сделать это? – aquirdturtle 21 May 2016 в 17:09
  • 2
    Вы можете изменить объект, на который указывает name , например. путем добавления к списку, если этот объект изменен. Не существует семантики Python для того, чтобы сказать «изменить пространство имен области действия, которая вызвала меня, чтобы имя в списке аргументов теперь указывало на нечто иное, чем когда оно называлось мной». – Kirk Strauser 21 May 2016 в 18:19
  • 3
    Фактически я спрашиваю, есть ли простой способ заставить python не создавать новый указатель на тот же объект, но вместо этого использовать оригинальный указатель. Я понимаю, что нет никакого способа сделать это. Я беру это из других ответов, что нормальная работа для достижения того, что происходит с помощью ссылки, - это просто вернуть больше параметров. если это так, я вижу некоторую справедливость в аргументе, что a, b, c, d, e = foo (a, b, c, d, e) немного более неуклюжи, чем просто foo (a, b, c, д, е). – aquirdturtle 21 May 2016 в 19:13
-1
ответ дан Casper Ghost 21 August 2018 в 20:39
поделиться

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

l = [0]

def set_3(x):
    x[0] = 3

set_3(l)
print(l[0])

В приведенном выше коде функция изменяет содержимое объекта List (который является изменяемым), и поэтому выход равен 3 вместо 0.

Я пишу этот ответ только для иллюстрации того, что означает «по значению» в Python. Вышеупомянутый код плохой стиль, и если вы действительно хотите изменить свои значения, вы должны написать класс и методы вызова в этом классе, как предлагает MPX.

2
ответ дан Isaac 21 August 2018 в 20:39
поделиться
  • 1
    это отвечает на половину вопроса, так как бы написать одну и ту же функцию set_3 (x), чтобы она не меняла значение l, а возвращала новый список, который был изменен? – Timothy Lawman 9 November 2012 в 01:31
  • 2
    Просто создайте новый список и измените его: y = [a for a in x]; y[0] = 3; return y – Isaac 9 November 2012 в 01:35
  • 3
    – Timothy Lawman 9 November 2012 в 01:47
  • 4
    Вы не можете изменить примитивный аргумент, например, int. Вы должны положить его в какой-то контейнер. Мой пример помещает его в список. Вы также можете поместить его в класс или словарь. На самом деле, вы должны просто переназначить его вне функции с чем-то вроде x = foo(x). – Isaac 9 November 2012 в 01:51

В Python передача по ссылке или по значению имеет отношение к тому, каковы фактические объекты, которые вы передаете. Так что, если вы передаете список, например, вы фактически делаете этот проход по ссылке, поскольку этот список является изменяемый объект. Таким образом, вы передаете указатель на функцию, и вы можете изменить объект (список) в теле функции.

Когда вы передаете строку, эта передача выполняется по значению, поэтому создается новый строковый объект, и когда функция завершается, он уничтожается. Таким образом, все это связано с изменяемыми и неизменяемыми объектами.

-2
ответ дан jkalivas 21 August 2018 в 20:39
поделиться
  • 1
    Это совершенно неверно. Python всегда проходит через «ссылку на объект». (который отличается от переменной ссылки). – Kirk Strauser 9 November 2012 в 02:20
  • 2
    я имел в виду аналоговые изменчивые объекты - передайте по ссылке и неизменяемым объектам - передайте по значению. Это совершенно верно, что я говорю. Вероятно, вы не заметили, что я говорю – jkalivas 9 November 2012 в 22:56
  • 3
    Я поймал это, и это неправильно. Он не имеет никакого отношения к тому, является ли объект изменчивым или неизменным; это всегда делается так же. – Kirk Strauser 9 November 2012 в 23:31

Python не является ни передачей по значению, ни передачей по ссылке. Это больше «ссылки на объекты передаются по значению», как описано здесь: http://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip- к-член / .

  1. Вот почему это не пропускная способность. Поскольку def append (list): list.append (1) list = [0] переназначить (список) append (list)

возвращает [0,1], показывая, что какая-то ссылка была явно передается как pass-by-value, не позволяет функции изменять родительскую область вообще.

Похоже, что pass-by-reference, hu? Нет.

  1. Вот почему это не перекрестная ссылка. Поскольку def reassign (list): list = [0, 1] list = [0] переназначить (список) список печати

возвращает [0], показывая, что исходная ссылка была уничтожена, когда список был переназначены. pass-by-reference вернул бы [0,1].

Для получения дополнительной информации смотрите здесь: http://effbot.org/zone/call-by-object.htm

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

from copy import copy

def append(list):
  list2 = copy(list)
  list2.append(1)
  print list2

list = [0]
append(list)
print list
7
ответ дан Philip Dodson 21 August 2018 в 20:39
поделиться
83
ответ дан Shobhit Verma 21 August 2018 в 20:39
поделиться

Ответ представлен

def set_4(x):
   y = []
   for i in x:
       y.append(i)
   y[0] = 4
   return y

и

l = [0]

def set_3(x):
     x[0] = 3

set_3(l)
print(l[0])

, что является лучшим ответом, поскольку он делает то, что он говорит в вопросе. Тем не менее, это выглядит очень неуклюжим способом по сравнению с VB или Pascal. Это лучший метод, который у нас есть?

Не только неуклюже, но и связано с изменением исходного параметра каким-либо образом вручную, например, путем изменения первоначальный параметр в список: или копирование его в другой список, а не просто: «используйте этот параметр как значение» или «используйте его как ссылку». Может ли простой ответ быть зарезервированным для этого, но это отличная работа?

0
ответ дан Timothy Lawman 21 August 2018 в 20:39
поделиться
Другие вопросы по тегам:

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