Как передать целое число по ссылке в Python?
Я хочу изменить значение переменной, которую передаю функции. Я читал, что в Python все передается по значению, но должен быть простой трюк. Например, в Java можно передать эталонные типы Integer
, Long
и т.д.
- Как передать целое число в функцию по ссылке?
- Какие лучшие практики?
python
function
pass-by-reference
pass-by-value
CodeKingPlusPlus
источник
источник
Ответы:
В Python это не совсем так. Python передает ссылки на объекты. Внутри вашей функции у вас есть объект - вы можете изменить этот объект (если возможно). Однако целые числа неизменяемы . Один из способов обхода - передать целое число в контейнер, который можно изменить:
def change(x): x[0] = 3 x = [1] change(x) print x
Это в лучшем случае уродливо / неуклюже, но вы не добьетесь большего успеха в Python. Причина в том, что в Python assignment (
=
) берет любой объект, являющийся результатом правой стороны, и привязывает его к тому, что находится слева * (или передает его соответствующей функции).Понимая это, мы можем понять, почему нет способа изменить значение неизменяемого объекта внутри функции - вы не можете изменить ни один из его атрибутов, потому что он неизменяемый, и вы не можете просто присвоить «переменной» новый значение, потому что тогда вы фактически создаете новый объект (который отличается от старого) и даете ему имя, которое старый объект имел в локальном пространстве имен.
Обычно обходной путь - просто вернуть нужный объект:
def multiply_by_2(x): return 2*x x = 1 x = multiply_by_2(x)
* В первом примере выше
3
фактически передается вx.__setitem__
.источник
C
. (Например, их не нужно разыменовывать). В моей ментальной модели легче думать о вещах как о «именах» и «объектах». Присвоение связывает «Имя» (я) слева с «Объектом» (ами) справа. Когда вы вызываете функцию, вы передаете «Объект» (фактически привязывая его к новому локальному имени внутри функции)..
оператор просто разыменовывает левую часть. Операторы на разных языках могут быть разными.В большинстве случаев, когда вам нужно передать по ссылке, вам нужно вернуть более одного значения обратно вызывающей стороне. «Лучшая практика» - использовать несколько возвращаемых значений, что намного проще сделать в Python, чем в таких языках, как Java.
Вот простой пример:
def RectToPolar(x, y): r = (x ** 2 + y ** 2) ** 0.5 theta = math.atan2(y, x) return r, theta # return 2 things at once r, theta = RectToPolar(3, 4) # assign 2 things at once
источник
Не совсем прямая передача значения, а использование его, как если бы оно было передано.
x = 7 def my_method(): nonlocal x x += 1 my_method() print(x) # 8
Предостережения:
nonlocal
был введен в Python 3global
вместоnonlocal
.источник
На самом деле лучше всего сделать шаг назад и спросить, действительно ли вам это нужно. Почему вы хотите изменить значение переменной, которую передаете функции?
Если вам нужно сделать это для быстрого взлома, самый быстрый способ - передать
list
целое число и прикрепить его к[0]
каждому его использованию, как демонстрирует ответ mgilson.Если вам нужно сделать это для чего-то более значительного, напишите,
class
что имеетint
атрибут в качестве атрибута, чтобы вы могли просто установить его. Конечно, это заставляет вас придумать хорошее имя для класса и для атрибута - если вы ничего не можете придумать, вернитесь и прочтите предложение еще раз несколько раз, а затем используйтеlist
.В более общем смысле, если вы пытаетесь перенести какую-то идиому Java непосредственно на Python, вы делаете это неправильно. Даже когда есть что-то прямо соответствующее (как с
static
/@staticmethod
), вы все равно не хотите использовать это в большинстве программ Python только потому, что вы использовали бы это в Java.источник
В Python каждое значение является ссылкой (указателем на объект), как и в Java без примитивов. Кроме того, как и в Java, Python имеет передачу только по значению. Итак, семантически они почти одинаковы.
Поскольку вы упоминаете Java в своем вопросе, я хотел бы увидеть, как вы добиваетесь того, чего хотите от Java. Если вы можете показать это на Java, я могу показать вам, как это сделать в точности эквивалентно на Python.
источник
NumPy массив с одним элементом является изменяемым и тем не менее в большинстве случаев, это может быть оценена , как если бы это была числовая переменная Python. Следовательно, это более удобный контейнер по ссылочным номерам, чем одноэлементный список.
import numpy as np def triple_var_by_ref(x): x[0]=x[0]*3 a=np.array([2]) triple_var_by_ref(a) print(a+1)
выход:
3
источник
class PassByReference: def Change(self, var): self.a = var print(self.a) s=PassByReference() s.Change(5)
источник
Может это не питонический способ, но вы можете это сделать
import ctypes def incr(a): a += 1 x = ctypes.c_int(1) # create c-var incr(ctypes.ctypes.byref(x)) # passing by ref
источник
Может быть, немного более самодокументированный, чем уловка со списком длины 1, является старый трюк с пустым типом:
def inc_i(v): v.i += 1 x = type('', (), {})() x.i = 7 inc_i(x) print(x.i)
источник
В Python все передается по значению, но если вы хотите изменить какое-либо состояние, вы можете изменить значение целого числа внутри списка или объекта, передаваемого методу.
источник
everything is passed by value
это не совсем так. Цитата docs:arguments are passed using call by value (where the value is always an object reference, not the value of the object)
Правильный ответ - использовать класс и поместить значение внутри класса, это позволяет передавать по ссылке точно так, как вы хотите.
class Thing: def __init__(self,a): self.a = a def dosomething(ref) ref.a += 1 t = Thing(3) dosomething(t) print("T is now",t.a)
источник