Pergunta

A documentação Python parece incerto sobre se os parâmetros são passados ??por referência ou valor, e o seguinte código produz o valor inalterado 'Original'

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change(self.variable)
        print(self.variable)

    def change(self, var):
        var = 'Changed'

Existe algo que eu possa fazer para passar a variável por referência real?

Foi útil?

Solução

Os argumentos são passou por cessão . A lógica por trás disso é duplo:

  1. o parâmetro passado é realmente um referência para um objeto (mas a referência é passado por valor)
  2. alguns tipos de dados são mutáveis, mas outros não são

Assim:

  • Se você passar um mutável objeto em um método, o método obtém uma referência a esse mesmo objeto e você pode sofrer mutação para deleite do seu coração, mas se você religar a referência no método, o escopo externo vai saber nada sobre isso, e depois que você fez, a referência externa ainda vai apontar para o objeto original.

  • Se você passar um imutável objeto para um método, você ainda não pode religar a referência externa, e você não pode mesmo transformar o objeto.

Para torná-lo ainda mais claro, vamos dar alguns exemplos.

Lista - um tipo mutável

Vamos tentar modificar a lista que foi passado para um método:

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)

Output:

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

Uma vez que o parâmetro passado é uma referência a outer_list, não uma cópia do mesmo, podemos usar os métodos da lista mutação para mudá-lo e ter as alterações refletidas no escopo externo.

Agora vamos ver o que acontece quando tentamos alterar a referência que foi passada como um parâmetro:

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)

Output:

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

Uma vez que o parâmetro the_list foi passada por valor, atribuindo uma nova lista a ele não teve efeito que o código fora do método podia ver. O the_list era uma cópia da referência outer_list, e tivemos ponto the_list a uma nova lista, mas não havia nenhuma maneira de mudar onde outer_list apontou.

String - um tipo imutável

É imutável, então não há nada que possamos fazer para alterar o conteúdo da string

Agora, vamos tentar alterar a referência

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)

Output:

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

Mais uma vez, já que o parâmetro the_string foi passada por valor, atribuindo uma nova seqüência a ele não teve efeito que o código fora do método podia ver. O the_string era uma cópia da referência outer_string, e tivemos ponto the_string para uma nova seqüência, mas não havia nenhuma maneira de mudar onde outer_string apontou.

Espero que isso esclarece as coisas um pouco.

EDIT: Tem sido notado que isto não responde a pergunta que @ David originalmente perguntou: "Existe algo que eu possa fazer para passar a variável por referência real?". Vamos trabalhar nisso.

Como é que vamos resolver isso?

Como @ mostra resposta de Andrea, você poderia retornar o novo valor. Isso não muda a forma como as coisas são passadas, mas não deixá-lo começar a informação que você quer de volta:

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)

Se você realmente queria evitar o uso de um valor de retorno, você poderia criar uma classe para manter o seu valor e passá-lo para a função ou usar uma classe existente, como uma lista:

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

Embora este parece um pouco complicado.

Outras dicas

O problema vem de um mal-entendido do que as variáveis ??estão em Python. Se você está acostumado a maioria das linguagens tradicionais, você tem um modelo mental do que acontece na sequência seguinte:

a = 1
a = 2

Você acredita que a é um local de memória que armazena o valor 1, em seguida, é atualizado para armazenar o valor 2. Isso não é como as coisas funcionam em Python. Em vez disso, a começa como uma referência a um objecto com o valor 1, então é transferido como uma referência a um objecto com o valor 2. Esses dois objetos podem continuar a coexistir, embora a não se refere ao primeiro mais; na verdade, eles podem ser compartilhados por qualquer número de outras referências dentro do programa.

Quando você chamar uma função com um parâmetro, uma nova referência é criado que se refere ao objeto passado. Esta é separada da referência que foi usado na chamada de função, então não há nenhuma maneira de atualizar essa referência e torná-lo referem-se a um novo objeto. No seu exemplo:

def __init__(self):
    self.variable = 'Original'
    self.Change(self.variable)

def Change(self, var):
    var = 'Changed'

self.variable é uma referência para o objeto String 'Original'. Quando você chama Change você criar uma segunda var referência ao objeto. Dentro da função volta a atribuir a var referência a um 'Changed' corda objeto diferente, mas o self.variable referência é separado e não muda.

A única maneira de contornar isso é para passar um objeto mutável. Porque ambas as referências se referem ao mesmo objeto, qualquer alteração no objeto são refletidas em ambos os lugares.

def __init__(self):         
    self.variable = ['Original']
    self.Change(self.variable)

def Change(self, var):
    var[0] = 'Changed'

Eu encontrei as outras respostas bastante longo e complicado, por isso criei este diagrama simples de explicar a maneira Python trata variáveis ??e parâmetros. enter descrição da imagem aqui

Não é nem passar por valor ou passar por referência - é chamada-a-objeto. Veja isso, por Fredrik Lundh:

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

Aqui está uma citação significativa:

"... variáveis ??[nomes] são não objetos;. Não podem ser indicados por outras variáveis ??ou referidos por objetos"

No seu exemplo, quando o método Change é chamado - um namespace é criado para ele; e var torna-se um nome, dentro desse namespace, para a cadeia objeto 'Original'. Esse objeto, em seguida, tem um nome em dois namespaces. Em seguida, liga var = 'Changed' var para um novo objeto string, e, portanto, do método esquece namespace cerca 'Original'. Finalmente, que namespace é esquecido, e o 'Changed' corda junto com ele.

Pense em coisas que está sendo passada por cessão em vez de por referência / por valor. Dessa forma, é allways clara, o que está acontecendo enquanto você entender o que acontece durante a atribuição normal.

Assim, ao passar uma lista para uma função / método, a lista é atribuída ao nome do parâmetro. Acrescentando à lista resultará na lista a ser modificada. Reatribuindo a lista dentro a função não vai mudar a lista original, uma vez que:

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

Desde tipos imutáveis ??não podem ser modificados, eles parecem como ser passados ??por valor - passar um int em um meio de função atribuindo o int para o parâmetro de funções. Você só pode jamais transferir isso, mas isso não vai mudar o valor variáveis ??originial.

Effbot (aka Fredrik Lundh) descreveu o estilo de passagem variável de Python como chamada por objeto: http: // effbot.org/zone/call-by-object.htm

Os objetos são alocados na pilha e ponteiros para eles pode ser passado ao redor em qualquer lugar.

  • Quando você faz uma atribuição como x = 1000, uma entrada de dicionário é criado que mapeia a cadeia "x" no namespace atual para um ponteiro para o objeto inteiro contendo mil.

  • Quando você atualizar "x" com x = 2000, um novo objeto inteiro é criado eo dicionário é atualizado para apontar para o novo objeto. O velho mil objeto permanece inalterado (e pode ou não pode estar vivo dependendo se qualquer outra coisa se refere ao objeto).

  • Quando você faz uma nova atribuição, como y = x, uma nova entrada de dicionário "y" é criado que aponta para o mesmo objeto que a entrada de "x".

  • objetos como strings e inteiros são imutável . Isto significa simplesmente que não existem métodos que podem alterar o objeto depois que ele foi criado. Por exemplo, uma vez que o objeto inteiro de mil é criado, ele nunca vai mudar. Math é feito através da criação de novos objetos inteiros.

  • Objetos como listas são mutável . Isto significa que o conteúdo do objeto pode ser alterado por qualquer coisa que aponta para o objeto. Por exemplo, x = []; y = x; x.append(10); print y imprimirá [10]. A lista vazia foi criado. Tanto o "x" e ponto "y" para a mesma lista. O append mutates método (atualizações) O objeto da lista (como a adição de um registro para um banco de dados) e o resultado é visível para ambos "x" e "y" (assim como uma atualização de banco de dados seria visível para cada conexão ao banco de dados).

Esperamos que esclarece a questão para você.

Tecnicamente, Python sempre usos passar por valores de referência . Eu vou repetir minha outra resposta para apoiar a minha declaração.

Python sempre usa os valores passados ??por referência. Não há qualquer exceção. Qualquer meio atribuição de variável copiar o valor de referência. Sem exceção. Qualquer variável é o nome ligado ao valor de referência. Sempre.

Você pode pensar em um valor de referência como o endereço do objeto de destino. O endereço é dereferenced automaticamente quando usado. Desta forma, trabalhando com o valor de referência, parece que você trabalhar diretamente com o objeto de destino. Mas sempre é uma referência no meio, mais um passo para saltar para o alvo.

Aqui está o exemplo que comprova que o Python usa passagem por referência:

Illustrated exemplo de passar o argumento

Se o argumento foi passado por valor, o lst exterior não pode ser modificado. O verde são os objectos alvo (a preto é o valor armazenado no interior, o vermelho é o tipo de objecto), o amarelo é a memória com o valor de referência dentro - desenhadas como a seta. A seta sólido azul é o valor de referência que foi passado para a função (por via do caminho seta tracejada azul). O amarelo escuro feio é o dicionário interno. (Na verdade, poderia ser desenhado também como uma elipse verde. A cor ea forma única diz que é interno.)

Você pode usar o id() função built-in para saber o que o valor de referência é (isto é, o endereço do objecto alvo).

Em linguagens compiladas, a variável é um espaço de memória que é capaz de capturar o valor do tipo. Em Python, a variável é um nome (capturado internamente como uma cadeia) ligado à variável de referência que mantém o valor de referência para o objecto alvo. O nome da variável é a chave no dicionário interno, a parte do valor desse item de dicionário armazena o valor de referência para o destino.

Os valores de referência estão escondidos em Python. Não há qualquer tipo explícita do usuário para armazenar o valor de referência. No entanto, é possível utilizar um elemento de lista (ou elemento em qualquer outro tipo de recipiente apropriado) como a variável de referência, porque todos os recipientes fazer armazenar os elementos também como referências aos objectos alvo. Em outras palavras, os elementos realmente não estão contidos dentro do recipiente - apenas as referências a elementos são

.

Um truque simples que eu normalmente uso é apenas para envolvê-la em uma lista:

def Change(self, var):
    var[0] = 'Changed'

variable = ['Original']
self.Change(variable)      
print variable[0]

(Sim, eu sei que isto pode ser inconveniente, mas às vezes é o suficiente simples de fazer isso.)

Não há variáveis ??em Python

A chave para a compreensão passagem de parâmetros é parar de pensar sobre "variáveis". Há nomes e objetos em Python e juntos aparecem como variáveis, mas é útil sempre distinguir os três.

  1. Python tem nomes e objetos.
  2. Assignment se liga um nome a um objeto.
  3. Passando um argumento em uma função também se liga um nome (o nome do parâmetro da função) a um objeto.

Isso é tudo que existe para ela. Mutabilidade é irrelevante para esta questão.

Exemplo:

a = 1

Este liga o nome a a um objecto de tipo inteiro que possui o valor 1.

b = x

Isso vincula o nome b para o mesmo objeto que o nome x está vinculado. Depois, o nome b não tem nada a ver com o nome x mais.

Veja seções 3.1 e 4.2 na referência da linguagem Python 3.

Como ler o exemplo na questão

No código mostrado na questão, o self.Change(self.variable) declaração vincula o var nome (no âmbito da função Change) para o objeto que detém o 'Original' valor eo var = 'Changed' atribuição (no corpo da função Change) atribui esse mesmo nome novamente:. para algum outro objeto (o que acontece para segurar uma corda tão bem, mas poderia ter sido algo completamente diferente)

Como passar por referência

(edit 2019/04/28)

Portanto, se a coisa que você quer a mudança é um objeto mutável, não há nenhum problema, como tudo é efetivamente passados ??por referência.

Se for um objeto imutável (por exemplo, um booleano, número, string), o caminho a percorrer é envolvê-lo em um objeto mutável.
A solução rápida e suja para isso é uma lista de um elemento (em vez de self.variable, passar [self.variable] e na função modificar var[0]).
A pythônico abordagem mais seria a introdução de uma classe trivial, um atributo. A função recebe uma instância da classe e manipula o atributo.

(edit - Blair actualiza a sua resposta extremamente popular de modo que agora é preciso)

Eu acho que é importante notar que o cargo atual com a maioria dos votos (por Blair Conrad), enquanto ser correto com relação ao seu resultado, é enganosa e está no limite incorreta com base em suas definições. Embora existam muitas linguagens (como C) que permitem que o usuário quer passar por referência ou passar por valor, Python não é um deles.

David Cournapeau resposta aponta para a resposta real e explica por que o comportamento no post de Blair Conrad parece ser correta, enquanto as definições não são.

Na medida em que Python é passar por valor, todos os idiomas são passar por valor desde algum pedaço de dados (seja ele um "valor" ou uma "referência") deve ser enviado. No entanto, isso não significa que Python é passar por valor no sentido de que um programador C pensaria nisso.

Se você quiser o comportamento, a resposta de Blair Conrad é bom. Mas se você quer saber as porcas e parafusos de por que Python é nem passar por valor ou passar por referência, leia a resposta de David Cournapeau.

Você tem alguns realmente boas respostas aqui.

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

Neste caso, a variável var intitulado na Change método é atribuída uma referência a self.variable e atribuir imediatamente uma corda para var. Já não está apontando para self.variable. O seguinte mostra trecho de código O que aconteceria se você modificar a estrutura de dados apontado pelo var e self.variable, neste caso uma lista:

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

Eu tenho certeza que alguém poderia esclarecer isso melhor.

esquema de passagem por atribuição do Python não é bem a mesma coisa 's opção de parâmetros de referência C ++ como, mas ele acaba por ser muito semelhante ao modelo de passagem de argumento da linguagem C (e outros) na prática:

  • argumentos imutáveis ??são efetivamente passou “ por valor .” Objetos como inteiros e strings são passados ??por referência objeto em vez de copiando, mas porque você não pode mudar objetos imutáveis ??no lugar de qualquer forma, o efeito é muito parecido com fazer uma cópia.
  • argumentos mutáveis ??são efetivamente passou “ por ponteiro .” Objetos como listas e dicionários também são passados ??por referência objecto, que é semelhante à forma C passes matrizes como objectos ponteiros-mutáveis ??podem ser alterados no lugar na função, bem como matrizes C.

Como você pode afirmar que você precisa ter um objeto mutável, mas deixe-me sugerir-lhe verificar sobre as variáveis ??globais como eles podem ajudá-lo ou até mesmo resolver este tipo de problema!

http://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

exemplo:

>>> def x(y):
...     global z
...     z = y
...

>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'z' is not defined

>>> x(2)
>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
2

Um monte de insights em respostas aqui, mas acho que um ponto adicional não é claramente mencionado explicitamente aqui. Citando a documentação python https://docs.python.org/2/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

"Em Python, variáveis ??que apenas são referenciados dentro de uma função são implicitamente global. Se uma variável é atribuído um novo lugar valor dentro do corpo da função, é assumido a ser um local. Se uma variável é sempre atribuído um novo valor dentro a função, a variável é implicitamente local, e você precisa declará-la explicitamente como 'global'. Embora um pouco surpreendente à primeira vista, um momento de consideração explica isso. Por um lado, exigindo global para variáveis ??atribuídas fornece um bar contra os efeitos colaterais indesejados. Por outro lado, se mundial foi necessário para todas as referências globais, você estaria usando global de todo o tempo. Você teria que declarar tão global cada referência a um built-in função ou a um componente de um módulo importado. Esta desordem iria derrotar a utilidade da declaração global para identificar efeitos colaterais ".

Mesmo quando passar um objeto mutável para uma função esta ainda se aplica. E para mim explica claramente a razão para a diferença de comportamento entre atribuindo ao objeto e operando no objeto na função.

def test(l):
    print "Received", l , id(l)
    l = [0, 0, 0]
    print "Changed to", l, id(l)  # New local object created, breaking link to global l

l= [1,2,3]
print "Original", l, id(l)
test(l)
print "After", l, id(l)

dá:

Original [1, 2, 3] 4454645632
Received [1, 2, 3] 4454645632
Changed to [0, 0, 0] 4474591928
After [1, 2, 3] 4454645632

A atribuição a uma variável global que não é declarado mundial, portanto, cria um novo objeto e breaks local, o link para o objeto original.

Aqui é o simples (espero) explicação do pass by object conceito utilizado em Python.
Sempre que você passar um objeto para a função, o próprio objeto é passado (objeto em Python é realmente o que você chamaria de um valor em outras linguagens de programação) não a referência a este objeto. Em outras palavras, quando você chama:

def change_me(list):
   list = [1, 2, 3]

my_list = [0, 1]
change_me(my_list)

O objeto real - [0, 1] (que seria chamado de um valor em outras linguagens de programação) está sendo passado. Então, na verdade a função change_me vai tentar fazer algo como:

[0, 1] = [1, 2, 3]

que, obviamente, não vai mudar o objeto passado para a função. Se a função ficou assim:

def change_me(list):
   list.append(2)

Em seguida, a chamada resultaria em:

[0, 1].append(2)

que, obviamente, vai mudar o objeto. Esta resposta explica-lo bem.

Além de todas as grandes explicações sobre como essa coisa funciona em Python, eu não vejo uma simples sugestão para o problema. Como você parece fazer criar objetos e instâncias, a maneira Python de lidar com variáveis ??de instância e alterá-los é o seguinte:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.Change()
        print self.variable

    def Change(self):
        self.variable = 'Changed'

Em métodos de instância, você normalmente se referem a self aos atributos de instância de acesso. É normal para definir atributos instância em __init__ e ler ou alterá-los em métodos de instância. É também por isso você passar als self o primeiro argumento para def Change.

Outra solução seria a criação de um método estático como este:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.variable = PassByReference.Change(self.variable)
        print self.variable

    @staticmethod
    def Change(var):
        var = 'Changed'
        return var

Há um pequeno truque para passar um objeto por referência, mesmo que a linguagem não torná-lo possível. Ele funciona em Java também, é a lista com um item. ; -)

class PassByReference:
    def __init__(self, name):
        self.name = name

def changeRef(ref):
    ref[0] = PassByReference('Michael')

obj = PassByReference('Peter')
print obj.name

p = [obj] # A pointer to obj! ;-)
changeRef(p)

print p[0].name # p->name

É um corte feio, mas funciona. ;-P

Eu usei o seguinte método para converter rapidamente um par de códigos Fortran para Python. É verdade, não é passar por referência, como a pergunta original foi colocada, mas é um trabalho simples ao redor em alguns casos.

a=0
b=0
c=0
def myfunc(a,b,c):
    a=1
    b=2
    c=3
    return a,b,c

a,b,c = myfunc(a,b,c)
print a,b,c

Enquanto passagem por referência é nada que se encaixa bem em python e raramente deve ser usado há algumas soluções alternativas que realmente podem trabalhar para obter o objeto atualmente atribuído a uma variável local ou mesmo transferir uma variável local a partir de dentro de uma função chamada.

A idéia básica é ter uma função que pode fazer que o acesso e pode ser passado como objeto em outras funções ou armazenada em uma classe.

Uma forma é a utilização global (para variáveis ??globais) ou nonlocal (para variáveis ??locais em uma função) em uma função wrapper.

def change(wrapper):
    wrapper(7)

x = 5
def setter(val):
    global x
    x = val
print(x)

A mesma idéia funciona para leitura e deleting uma variável.

Para ler apenas há ainda um caminho mais curto de apenas usar lambda: x que retorna um exigível que, quando chamada retorna o valor atual de x. Isto é um pouco como "chamar pelo nome" usado em línguas no passado distante.

Passando 3 wrappers para acessar a variável é um pouco pesado para que aqueles podem ser embrulhados em uma classe que tem um atributo proxy:

class ByRef:
    def __init__(self, r, w, d):
        self._read = r
        self._write = w
        self._delete = d
    def set(self, val):
        self._write(val)
    def get(self):
        return self._read()
    def remove(self):
        self._delete()
    wrapped = property(get, set, remove)

# left as an exercise for the reader: define set, get, remove as local functions using global / nonlocal
r = ByRef(get, set, remove)
r.wrapped = 15

Pythons apoio "reflexão" faz com que seja possível obter um objeto que é capaz de reatribuir um nome / variável em um determinado escopo sem definir funções explicitamente nesse âmbito:

class ByRef:
    def __init__(self, locs, name):
        self._locs = locs
        self._name = name
    def set(self, val):
        self._locs[self._name] = val
    def get(self):
        return self._locs[self._name]
    def remove(self):
        del self._locs[self._name]
    wrapped = property(get, set, remove)

def change(x):
    x.wrapped = 7

def test_me():
    x = 6
    print(x)
    change(ByRef(locals(), "x"))
    print(x)

Aqui a classe ByRef envolve um acesso dicionário. Assim, o acesso atributo para wrapped é traduzido para um acesso item no dicionário passou. Ao passar o resultado da locals builtin e o nome de uma variável local Isso acaba acessando uma variável local. A documentação python a partir de 3,5 aconselha que a mudança do dicionário pode não funcionar, mas parece trabalhar para mim.

dada a forma como os valores alças Python e referências a eles, a única maneira que você pode fazer referência a um atributo de instância arbitrária é pelo nome:

class PassByReferenceIsh:
    def __init__(self):
        self.variable = 'Original'
        self.change('variable')
        print self.variable

    def change(self, var):
        self.__dict__[var] = 'Changed'

no código real, você seria, naturalmente, erro add controlo sobre a pesquisa dict.

Pass-By-Reference em Python é bastante diferente do conceito de passagem por referência em C ++ / Java.

  • Java e C #: tipos primitivos (incluem string) passar por valor (cópia), tipo de referência é passado por referência (cópia endereço) para que todas as alterações feitas no parâmetro na função de chamada são visíveis para o chamador.
  • C ++: são permitidos Ambos passagem por referência ou passar por valor. Se um parâmetro é passado por referência, você pode modificá-lo ou não, dependendo se o parâmetro foi passado como const ou não. No entanto, const ou não, o parâmetro mantém a referência ao objeto e de referência não pode ser atribuído a apontar para um objeto diferente dentro da função chamada.
  • Python: Python é “pass-by-objeto de referência”, da qual muitas vezes é dito: “As referências de objeto são passados ??por valor” [Leia aqui] 1 . Tanto o chamador e a função se referem ao mesmo objeto, mas o parâmetro na função é uma nova variável que está apenas segurando uma cópia do objeto no chamador. Como C ++, um parâmetro pode ser modificado ou não, em função - Este depende do tipo de objecto transmitido. por exemplo; Um tipo de objeto imutável não pode ser modificado na função chamada enquanto um objeto mutável pode ser ou atualizado ou re-inicializado. A diferença crucial entre atualizar ou atribuir re-re-inicializar a variável / mutável é que valor atualizado é refletido de volta na função chamada enquanto o valor reinicializado não. Âmbito de qualquer cessão de novo objeto para uma variável mutável é local para a função no python. Exemplos fornecidos pelo @ blair-Conrad são grandes para entender isso.

Uma vez que o seu exemplo passa a ser orientada a objetos, você poderia fazer o seguinte alteração para alcançar um resultado semelhante:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change('variable')
        print(self.variable)

    def change(self, var):
        setattr(self, var, 'Changed')

# o.variable will equal 'Changed'
o = PassByReference()
assert o.variable == 'Changed'

Uma vez que parece estar em nenhum lugar mencionado uma abordagem para referências simular o mais conhecido a partir de, por exemplo, C ++ é usar uma função de "update" e passar que, em vez da variável real (ou melhor, "nome"):

def need_to_modify(update):
    update(42) # set new value 42
    # other code

def call_it():
    value = 21
    def update_value(new_value):
        nonlocal value
        value = new_value
    need_to_modify(update_value)
    print(value) # prints 42

Isto é principalmente útil para "referências fora-only" ou em uma situação com vários segmentos / processos (fazendo o fio função de atualização / multiprocessamento seguro).

Obviamente, o acima não permite leitura o valor apenas atualizá-lo.

Você pode simplesmente usar uma classe vazia como uma instância de referência armazenar objetos porque internamente atributos de objeto são armazenados em um dicionário de instância. Veja o exemplo.

class RefsObj(object):
    "A class which helps to create references to variables."
    pass

...

# an example of usage
def change_ref_var(ref_obj):
    ref_obj.val = 24

ref_obj = RefsObj()
ref_obj.val = 1
print(ref_obj.val) # or print ref_obj.val for python2
change_ref_var(ref_obj)
print(ref_obj.val)

Desde dicionários são passados ??por referência, você pode usar uma variável dict para armazenar todos os valores referenciados dentro dela.

# returns the result of adding numbers `a` and `b`
def AddNumbers(a, b, ref): # using a dict for reference
    result = a + b
    ref['multi'] = a * b # reference the multi. ref['multi'] is number
    ref['msg'] = "The result: " + str(result) + " was nice!" # reference any string (errors, e.t.c). ref['msg'] is string
    return result # return the sum

number1 = 5
number2 = 10
ref = {} # init a dict like that so it can save all the referenced values. this is because all dictionaries are passed by reference, while strings and numbers do not.

sum = AddNumbers(number1, number2, ref)
print("sum: ", sum)             # the return value
print("multi: ", ref['multi'])  # a referenced value
print("msg: ", ref['msg'])      # a referenced value
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top