Passagem de argumento de funcao por referencia

classic Classic list List threaded Threaded
20 messages Options
Reply | Threaded
Open this post in threaded view
|

Passagem de argumento de funcao por referencia

Adriano Ogata
Bom dia Lista,


Como seria a forma pythônica para passagem de argumento por
referência? Por exemplo:

x = 1
process(x)
assert x == 2

Até onde vi não é possível algo desse tipo, já que x guarda uma
referência para o dado e, ao passar por parâmetro, é feita uma cópia
dessa referência. Então alterações locais à função não refletem na
variável externa. Uma solução que imaginei foi utilizar algum
container:

params = {"x": 1}
process(params)
assert params["x"] == 1

Alguém saberia me dizer se existe uma forma preferida de se manipular
variáveis assim? Sei que eu poderia fazer o retorno das variáveis (até
várias ao mesmo tempo), mas isso não sanaria minha dúvida. :]


Og!
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Luciano Ramalho
2010/4/1 Adriano Ogata <[hidden email]>:

> Bom dia Lista,
>
>
> Como seria a forma pythônica para passagem de argumento por
> referência? Por exemplo:
>
> x = 1
> process(x)
> assert x == 2
>
> Até onde vi não é possível algo desse tipo, já que x guarda uma
> referência para o dado e, ao passar por parâmetro, é feita uma cópia
> dessa referência. Então alterações locais à função não refletem na
> variável externa.

Python foi projetado assim mesmo. Mas eu não entendo o caso de uso que
justifica a sua necessidade. Porque não fazer assim:

x = 1
x = process(x)
assert x == 2

> Uma solução que imaginei foi utilizar algum
> container:
>
> params = {"x": 1}
> process(params)
> assert params["x"] == 1

Sim, isso funciona. Mas eu ainda não estou vendo o caso de uso que
justifica essa necessidade. Confesso que eu conenheço uma
justificativa, mas é um caso tão específico, num contexto tão
particular, que nem vou mencionar agora para não desviar o assunto.

> Alguém saberia me dizer se existe uma forma preferida de se manipular
> variáveis assim? Sei que eu poderia fazer o retorno das variáveis (até
> várias ao mesmo tempo), mas isso não sanaria minha dúvida. :]

Qual é o caso de uso que justifica essa necessidade, Og?

[ ]s
Luciano
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Paulo Eduardo Neves-3
In reply to this post by Adriano Ogata
Adriano,
qualquer argumento será passado como referência.  Se não for um tipo
imutável, isto é que seja  um objeto instanciado de uma classe, lista
ou dicionário, ao modificá-lo dentro da função, você modificará o
objeto fora.

O que não existe é passagem de argumento por valor. Nunca os
argumentos da função são copiados ao se chamar uma função. Na verdade
o que é diferente em Python é a semântica da atribuição.

Quando você faz atribuições, veja o que acontece ao pegar o endereço
do objeto com a função id():
>>> a = 1.1  # o nome "a" referencia o float 1.1
>>> id (a)  #endereço para o qual "a" aponta
152742508
>>> b  = a # o nome "b" aponta para o mesmo objeto que "a"
>>> id(a)
152742508
>>> c = 1.1 # o nome "c" aponta para uma outra instância float com valor 1.1
>>> id(c)
152742524
>>> a = 2.0  #fiz "a" referenciar para outro objeto float. "b" continua referenciando o objeto antigo
>>> id(a)
152706388
>>> id(b)
152742508

Nota: se você fizer isto com pequenas strings ou inteiros o
interpretador pode fazer umas otimizações e o id repetir resultados.

Lembre-se que os tipos básicos (int, float, string) são imutáveis,
portanto uma vez criados não podem ter seu valor modificado. O que
você sempre faz é apenas instanciar novos objetos fazer umas variáveis
referenciá-los:

>>> a = "a"
>>> b = a
>>> id(a), id(b)
(1074166240, 1074166240)
>>> a += "b"
>>> id(a), id(b)
(1074394688, 1074166240)

Espero não ter "confundido":-)

2010/4/1 Adriano Ogata <[hidden email]>:

> Bom dia Lista,
>
>
> Como seria a forma pythônica para passagem de argumento por
> referência? Por exemplo:
>
> x = 1
> process(x)
> assert x == 2
>
> Até onde vi não é possível algo desse tipo, já que x guarda uma
> referência para o dado e, ao passar por parâmetro, é feita uma cópia
> dessa referência. Então alterações locais à função não refletem na
> variável externa. Uma solução que imaginei foi utilizar algum
> container:
>
> params = {"x": 1}
> process(params)
> assert params["x"] == 1
>
> Alguém saberia me dizer se existe uma forma preferida de se manipular
> variáveis assim? Sei que eu poderia fazer o retorno das variáveis (até
> várias ao mesmo tempo), mas isso não sanaria minha dúvida. :]
>
>
> Og!
>
--
Paulo Eduardo Neves
http://www.mosquito.pro.br
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Paulo Eduardo Neves-3
Ops, eu errei na linha embaixo. Era para ser id(b), mas juro pra você
que será o mesmo resultado:-)

2010/4/1 Paulo Eduardo Neves <[hidden email]>:
>>>> b  = a # o nome "b" aponta para o mesmo objeto que "a"
>>>> id(a)
> 152742508



--
Paulo Eduardo Neves
http://www.mosquito.pro.br
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Adriano Ogata
In reply to this post by Luciano Ramalho
>> Como seria a forma pythônica para passagem de argumento por
>> referência? Por exemplo:
>>
>> x = 1
>> process(x)
>> assert x == 2
(...)
> Mas eu ainda não estou vendo o caso de uso que
> justifica essa necessidade. Confesso que eu conenheço uma
> justificativa, mas é um caso tão específico, num contexto tão
> particular, que nem vou mencionar agora para não desviar o assunto.

Tentei utilizar um dicionário pra manter minhas variáveis. Resolveu,
mas ficou ruim. No final acho que uma solução é o que você sugeriu
mesmo: fazer através do retorno da função. No meu caso eu já tinha
algo para retornar, então o jeito parece ser retornar uma lista.

Eu gostaria de algo assim:

x = 1
if process(x):
    assert x == 2

A função 'process' retorna um booleano, mas também altera o valor do
parâmetro x. Pensando em retornar uma lista, imagino que uma solução
seria:

x = 1
x, result = process(x)
if result:
    assert x == 2

Dessa forma já seria aceitável? (aceitável = sem muito sotaque de
outras linguagens)

> Qual é o caso de uso que justifica essa necessidade, Og?

Na verdade pensei melhor e vi que retornar vários valores resolve sim
o problema. Então a questão ficou só pelo lado da curiosidade mesmo.
Curioso foi que, mexendo quase que exclusivamente em python nos
últimos meses, eu só tenha esbarrado nessa questão agora. Daí surgiu
aquela situação: "se eu *quisesse* fazer algo equivalente, como seria
em python?".


Og!
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

George Ribeiro
Sei que acaba fugindo do assunto da thread, mas como ela já está resolvida
bateu a curiosidade. Que caso tão particular de uso é esse Luciano que você
falou na sua resposta?


[As partes desta mensagem que não continham texto foram removidas]

Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Adriano Ogata
In reply to this post by Paulo Eduardo Neves-3
(...)
> O que não existe é passagem de argumento por valor. Nunca os
> argumentos da função são copiados ao se chamar uma função. Na verdade
> o que é diferente em Python é a semântica da atribuição.

def f(param):
    print id(param)
    param = []
    print id(param)

x = [0, 1]
f(x)
assert (0 in x) and (1 in x)

A etiqueta 'x' possui um id. Ao passá-lo como parâmetro para f esse id
é copiado para uma nova etiqueta 'param'. Era isso que tinha em mente
quando utilizei 'passagem por valor'. Isso procede?

> Espero não ter "confundido":-)

Acho que não ;), está servindo pra validar o que tenho aprendido até agora.


Og!
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Danilo Cabello
In reply to this post by Adriano Ogata
2010/4/1 Adriano Ogata <[hidden email]>:
> Na verdade pensei melhor e vi que retornar vários valores resolve sim
> o problema. Então a questão ficou só pelo lado da curiosidade mesmo.
> Curioso foi que, mexendo quase que exclusivamente em python nos
> últimos meses, eu só tenha esbarrado nessa questão agora. Daí surgiu
> aquela situação: "se eu *quisesse* fazer algo equivalente, como seria
> em python?".

Mas isso que você quer fazer não se faz, adicionar funções soltas com
efeitos colaterais só vai complicar sua vida na manutenção do código
no curto, médio, longo prazo.

Use orientação a objetos a seu favor.
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Paulo Eduardo Neves-3
In reply to this post by Adriano Ogata
2010/4/1 Adriano Ogata <[hidden email]>:

> (...)
>> O que não existe é passagem de argumento por valor. Nunca os
>> argumentos da função são copiados ao se chamar uma função. Na verdade
>> o que é diferente em Python é a semântica da atribuição.
>
> def f(param):
>    print id(param)
>    param = []
>    print id(param)
>
> x = [0, 1]
> f(x)
> assert (0 in x) and (1 in x)
>
> A etiqueta 'x' possui um id. Ao passá-lo como parâmetro para f esse id
> é copiado para uma nova etiqueta 'param'. Era isso que tinha em mente
> quando utilizei 'passagem por valor'. Isso procede?

Gostei da sua tradução, variáveis são como "etiquetas". Acho que dá
uma boa ideia de como funcionam.

No caso, ao atribuir param = [], você mudou o que estava escrito na
etiqueta param. Passar uma lista e modificar a própria lista é a
semântica tradicional de referência.

def f(param):
  param.append('123')
x= []
f(x) #fará x == ['123']

ambos apontam para a mesma instância de objeto e o modificam internamente.

Nas linguagens tradicionais, uma variável não é uma etiqueta mas uma
espaço alocado em memória.

E retornar uma tupla para atribuir de uma vez a diversas variáveis é
um idioma bem comum em Python.


>
>> Espero não ter "confundido":-)
>
> Acho que não ;), está servindo pra validar o que tenho aprendido até agora.
>
>
> Og!
>



--
Paulo Eduardo Neves
http://www.mosquito.pro.br
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Adriano Ogata
>> A etiqueta 'x' possui um id. Ao passá-lo como parâmetro para f esse id
>> é copiado para uma nova etiqueta 'param'. Era isso que tinha em mente
>> quando utilizei 'passagem por valor'. Isso procede?
>
> Gostei da sua tradução, variáveis são como "etiquetas". Acho que dá
> uma boa ideia de como funcionam.

Só pra não levar os créditos dos outros, essa analogia eu vi numa
explicação do Luciano Ramalho, aqui na lista mesmo. ;)

> No caso, ao atribuir param = [], você mudou o que estava escrito na
> etiqueta param. Passar uma lista e modificar a própria lista é a
> semântica tradicional de referência.
>
> def f(param):
>  param.append('123')
> x= []
> f(x) #fará x == ['123']

Mas nesse caso você está alterando o parâmetro por meio de seus métodos, certo?

> ambos apontam para a mesma instância de objeto e o modificam internamente.
>
> Nas linguagens tradicionais, uma variável não é uma etiqueta mas uma
> espaço alocado em memória.

Acho que a analogia continua válida. Mas a diferença é, como você
mencionou no começo, a semântica da atribuição. Em python, durante uma
atribuição, um novo valor é escrito na etiqueta, se entendi bem.

> E retornar uma tupla para atribuir de uma vez a diversas variáveis é
> um idioma bem comum em Python.

É, gostei mais dessa solução mesmo.


Og!
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Adriano Ogata
In reply to this post by Danilo Cabello
> Mas isso que você quer fazer não se faz, adicionar funções soltas com
> efeitos colaterais só vai complicar sua vida na manutenção do código
> no curto, médio, longo prazo.
>
> Use orientação a objetos a seu favor.

Bem que gostaria. Mas nem sempre esse poder de decisão nos cabe. :]


Og!
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Luciano Ramalho
In reply to this post by Adriano Ogata
2010/4/1 Adriano Ogata <[hidden email]>:

> A função 'process' retorna um booleano, mas também altera o valor do
> parâmetro x. Pensando em retornar uma lista, imagino que uma solução
> seria:
>
> x = 1
> x, result = process(x)
> if result:
>    assert x == 2
>
> Dessa forma já seria aceitável? (aceitável = sem muito sotaque de
> outras linguagens)

Sim, eu acho ótima essa solução, e sem sotaque, porque inclusive usa
uma das características singulares de python que é uma função poder
devolver uma tupla de resultados, e vocẽ atribuir todos de uma vez.

[ ]s
Luciano
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Adriano Ogata
In reply to this post by George Ribeiro
2010/4/1 George Ribeiro <[hidden email]>:
> Sei que acaba fugindo do assunto da thread, mas como ela já está resolvida
> bateu a curiosidade. Que caso tão particular de uso é esse Luciano que você
> falou na sua resposta?

Também fiquei curioso. :]


Og!
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Adriano Ogata
In reply to this post by Luciano Ramalho
>> A função 'process' retorna um booleano, mas também altera o valor do
>> parâmetro x. Pensando em retornar uma lista, imagino que uma solução
>> seria:
>>
>> x = 1
>> x, result = process(x)
>> if result:
>>    assert x == 2
>>
>> Dessa forma já seria aceitável? (aceitável = sem muito sotaque de
>> outras linguagens)
>
> Sim, eu acho ótima essa solução, e sem sotaque, porque inclusive usa
> uma das características singulares de python que é uma função poder
> devolver uma tupla de resultados, e vocẽ atribuir todos de uma vez.

Certo, era o que eu queria saber. Obrigado Luciano, Paulo e Danilo
pelos comentários. Foram de grande ajuda!


Og!
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Narcélio Filho
In reply to this post by Luciano Ramalho
> > x = 1
> > x, result = process(x)
> > if result:
> >    assert x == 2
> >
> > Dessa forma já seria aceitável? (aceitável = sem muito sotaque de
> > outras linguagens)
> Sim, eu acho ótima essa solução, e sem sotaque, porque inclusive usa
> uma das características singulares de python que é uma função poder
> devolver uma tupla de resultados, e vocẽ atribuir todos de uma vez.

  Eu também uso esse tipo de idioma, mas se esse "result" serve para
verificar algum erro, sugiro usar um exception:

try:
    x = process(1)
except SeuErro:
    # trate seu erro aqui
else:
    assert x == 2


--
[]s, Narcélio

Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Luciano Ramalho
2010/4/2 Narcélio Filho <[hidden email]>:

>> > x = 1
>> > x, result = process(x)
>> > if result:
>> >    assert x == 2
>> >
>> > Dessa forma já seria aceitável? (aceitável = sem muito sotaque de
>> > outras linguagens)
>> Sim, eu acho ótima essa solução, e sem sotaque, porque inclusive usa
>> uma das características singulares de python que é uma função poder
>> devolver uma tupla de resultados, e vocẽ atribuir todos de uma vez.
>
>  Eu também uso esse tipo de idioma, mas se esse "result" serve para
> verificar algum erro, sugiro usar um exception:

Concordo, para sinalizar erros ou exceções, nada melhor que uma exceção!

[ ]s
Luciano
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

Luciano Ramalho
In reply to this post by George Ribeiro
2010/4/1 George Ribeiro <[hidden email]>:
> Sei que acaba fugindo do assunto da thread, mas como ela já está resolvida
> bateu a curiosidade. Que caso tão particular de uso é esse Luciano que você
> falou na sua resposta?

O exemplo é um tanto exotérico, OK?

O caso de uso envolve uma closure onde a função interna quer modificar
(e não apenas acessar) uma variável definida no escopo de uma função
externa.

Tem um exemplo disso no PEP-3104 que justifica a introdução da palavra
reservada nonlocal no Python 3.

http://www.python.org/dev/peps/pep-3104/

[ ]s
Luciano
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

George Ribeiro
Obrigado a explicação Luciano.


[As partes desta mensagem que não continham texto foram removidas]

Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

rafs
This post has NOT been accepted by the mailing list yet.
Bom sei que já se passaram anos desde a última postagem deste tópico, mas gostaria de deixar uma contribuição de meu blog, onde falo um pouco sobre a passagem de parâmetros:
http://www.rafs.com.br/parametros-por-referencia/
Reply | Threaded
Open this post in threaded view
|

Re: Passagem de argumento de funcao por referencia

rafs
This post has NOT been accepted by the mailing list yet.
In reply to this post by George Ribeiro
Bom sei que já se passaram anos desde a última postagem deste tópico, mas gostaria de deixar uma contribuição de meu blog, onde falo um pouco sobre a passagem de parâmetros:
http://www.rafs.com.br/parametros-por-referencia/