Como posso passar um inteiro por referência em Python?
Quero modificar o valor de uma variável que estou passando para a função. Eu li que tudo em Python é passado por valor, mas deve haver um truque fácil. Por exemplo, em Java você poderia passar os tipos de referência de Integer
, Long
, etc.
- Como posso passar um inteiro em uma função por referência?
- quais são as melhores práticas?
python
function
pass-by-reference
pass-by-value
CodeKingPlusPlus
fonte
fonte
Respostas:
Não funciona bem assim em Python. Python passa referências para objetos. Dentro de sua função, você tem um objeto - você está livre para modificar esse objeto (se possível). No entanto, os inteiros são imutáveis . Uma solução alternativa é passar o número inteiro em um contêiner que pode sofrer mutação:
def change(x): x[0] = 3 x = [1] change(x) print x
Isso é feio / desajeitado na melhor das hipóteses, mas você não vai se sair melhor em Python. A razão é porque no Python, atribuição (
=
) pega qualquer objeto que seja o resultado do lado direito e o vincula ao que estiver no lado esquerdo * (ou o passa para a função apropriada).Compreendendo isso, podemos ver porque não há como alterar o valor de um objeto imutável dentro de uma função - você não pode alterar nenhum de seus atributos porque é imutável, e você não pode simplesmente atribuir à "variável" um novo valor porque então você está realmente criando um novo objeto (que é diferente do antigo) e dando a ele o nome que o objeto antigo tinha no namespace local.
Normalmente, a solução alternativa é simplesmente retornar o objeto que você deseja:
def multiply_by_2(x): return 2*x x = 1 x = multiply_by_2(x)
* No primeiro caso de exemplo acima,
3
realmente é passado parax.__setitem__
.fonte
C
. (Eles não precisam ser referenciados, por exemplo). No meu modelo mental, é mais fácil pensar nas coisas como "Nomes" e "Objetos". A atribuição vincula "Nome" (s) à esquerda a "Objeto" (s) à direita. Ao chamar uma função, você passa o "Objeto" (vinculando-o efetivamente a um novo nome local dentro da função)..
operador simplesmente desreferencia o lado esquerdo. Os operadores podem ser diferentes em diferentes idiomas.A maioria dos casos em que você precisa passar por referência é onde você precisa retornar mais de um valor ao chamador. Uma "prática recomendada" é usar vários valores de retorno, o que é muito mais fácil de fazer em Python do que em linguagens como Java.
Aqui está um exemplo simples:
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
fonte
Não exatamente passando um valor diretamente, mas usando-o como se fosse passado.
x = 7 def my_method(): nonlocal x x += 1 my_method() print(x) # 8
Ressalvas:
nonlocal
foi introduzido em python 3global
vez denonlocal
.fonte
Na verdade, a prática recomendada é dar um passo atrás e perguntar se você realmente precisa fazer isso. Por quê que você deseja modificar o valor de uma variável que está passando para a função?
Se você precisar fazer isso para um hack rápido, a maneira mais rápida é passar um
list
segurando o inteiro e colocar um[0]
torno de cada uso dele, como a resposta de mgilson demonstra.Se você precisar fazer isso para algo mais significativo, escreva um
class
que tenha umint
como atributo, para que você possa apenas defini-lo. É claro que isso força você a encontrar um bom nome para a classe e para o atributo - se você não conseguir pensar em nada, volte e leia a frase novamente algumas vezes e, em seguida, use olist
.De modo mais geral, se você está tentando portar algum idioma Java diretamente para Python, está fazendo isso errado. Mesmo quando há algo diretamente correspondente (como com
static
/@staticmethod
), você ainda não deseja usá-lo na maioria dos programas Python apenas porque o usaria em Java.fonte
Em Python, todo valor é uma referência (um ponteiro para um objeto), assim como os não primitivos em Java. Além disso, como Java, Python só tem passagem por valor. Então, semanticamente, eles são praticamente os mesmos.
Já que você mencionou Java em sua pergunta, gostaria de ver como você consegue o que deseja em Java. Se você pode mostrar em Java, posso mostrar como fazer exatamente de forma equivalente em Python.
fonte
Uma matriz numpy de elemento único é mutável e, ainda assim, para a maioria dos propósitos, pode ser avaliada como se fosse uma variável python numérica. Portanto, é um contêiner de número por referência mais conveniente do que uma lista de elemento único.
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)
resultado:
3
fonte
Talvez não seja a forma pítônica, mas você pode fazer isso
import ctypes def incr(a): a += 1 x = ctypes.c_int(1) # create c-var incr(ctypes.ctypes.byref(x)) # passing by ref
fonte
class PassByReference: def Change(self, var): self.a = var print(self.a) s=PassByReference() s.Change(5)
fonte
Talvez um pouco mais autodocumentado do que o truque da lista de comprimento 1 seja o velho truque do tipo vazio:
def inc_i(v): v.i += 1 x = type('', (), {})() x.i = 7 inc_i(x) print(x.i)
fonte
Em Python, tudo é passado por valor, mas se você quiser modificar algum estado, pode alterar o valor de um inteiro dentro de uma lista ou objeto que é passado para um método.
fonte
everything is passed by value
não é verdade. Citar documentos:arguments are passed using call by value (where the value is always an object reference, not the value of the object)
A resposta correta, é usar uma classe e colocar o valor dentro da classe, isso permite que você passe por referência exatamente como deseja.
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)
fonte