web-dev-qa-db-ja.com

参照によって変数を渡す方法

Pythonのドキュメントでは、パラメータが参照と値のどちらで渡されるかについては不明確で、次のコードでは変更されていない値 'Original'が生成されます。

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

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

実際の参照によって変数を渡すために私にできることはありますか?

2309
David Sykes

引数は 代入によって渡されます 。この背景にある理論的根拠は2つあります。

  1. 渡されるパラメータは、実際にはオブジェクトへのreferenceです(ただし、参照は値渡しされます)
  2. 変更可能なデータ型もあれば、そうでないものもあります。

そう:

  • メソッドにmutableオブジェクトを渡すと、そのメソッドはその同じオブジェクトへの参照を取得し、それをあなたの心の喜びに変えることができます。それについては何も、そしてあなたがした後、外側の参照はまだ元のオブジェクトを指すでしょう。

  • メソッドにimmutableオブジェクトを渡しても、外部参照を再バインドすることはできず、オブジェクトを変更することすらできません。

より明確にするために、いくつか例を挙げましょう。

リスト - 可変型

メソッドに渡されたリストを修正してみましょう:

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)

出力:

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

渡されたパラメータはouter_listへの参照であり、そのコピーではないので、変更リストメソッドを使用してそれを変更し、変更を外側のスコープに反映させることができます。

パラメータとして渡された参照を変更しようとするとどうなるかを見てみましょう:

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)

出力:

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

the_listパラメータが値渡しされたので、それに新しいリストを代入してもメソッドの外側のコードが見ることができるという効果はありませんでした。 the_listouter_list参照のコピーであり、the_listに新しいリストを指すようにしましたが、outer_listが指す場所を変更する方法はありませんでした。

String - 不変の型

不変なので、文字列の内容を変更するためにできることは何もありません

それでは、参照を変更してみましょう

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)

出力:

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

繰り返しますが、the_stringパラメータは値渡しされているので、新しい文字列を代入しても、メソッドの外側のコードには影響がありません。 the_stringouter_string参照のコピーであり、the_stringは新しい文字列を指すようにしましたが、outer_stringが指す場所を変更する方法はありませんでした。

私はこれが物事を少しクリアすることを願っています。

編集: @Davidが最初に尋ねた「実際の参照によって変数を渡すためにできることはありますか」という質問に答えないことに注意してください。それに取り組みましょう。

これをどのように回避しますか。

@ Andreaの答えが示すように、新しい値を返すことができます。これは、物の受け渡し方法を変えることはありませんが、必要な情報を取り戻すことができます。

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)

戻り値の使用を避けたい場合は、値を保持して関数に渡すクラスを作成するか、リストのように既存のクラスを使用することができます。

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

これは少し面倒なようですが。

2491
Blair Conrad

問題は、Pythonにはどのような変数があるのか​​という誤解から生じます。あなたが最も伝統的な言語に慣れているなら、あなたは以下の順序で起こることの精神的モデルを持っています:

a = 1
a = 2

aは、値1を格納し、次に値2を格納するように更新されるメモリ位置です。それはPythonで物事がどのように機能するかではありません。そうではなく、aは値1を持つオブジェクトへの参照として始まり、次に値2を持つオブジェクトへの参照として再割り当てされます。 aが最初のオブジェクトを参照しなくなっても、これら2つのオブジェクトは共存し続ける可能性があります。実際、それらはプログラム内の他の多くの参照と共有される可能性があります。

パラメータを指定して関数を呼び出すと、渡されたオブジェクトを参照する新しい参照が作成されます。これは、関数呼び出しで使用された参照とは別のものであるため、その参照を更新して新しいオブジェクトあなたの例では:

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

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

self.variableは、文字列オブジェクト'Original'への参照です。 Changeを呼び出すと、オブジェクトへの2番目の参照varが作成されます。関数内で、参照varを別の文字列オブジェクト'Changed'に再割り当てしますが、参照self.variableは別のものであり変更されません。

これを回避する唯一の方法は、可変オブジェクトを渡すことです。両方の参照が同じオブジェクトを参照しているため、オブジェクトへの変更は両方の場所に反映されます。

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

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

私は他の答えはかなり長く複雑であると思ったので、この簡単な図を作成してPythonが変数とパラメータをどのように扱うかを説明しました。 enter image description here

280
Zenadix

値渡しでも参照渡しでもありません。オブジェクト呼び出しです。 Fredrik Lundhによるこれを参照してください。

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

これは重要な引用です:

「... variables [names]はnotオブジェクトです。他の変数で表すことも、オブジェクトで参照することもできません。」

あなたの例では、Changeメソッドが呼び出されると、 - 名前空間 がそれに対して作成されます。そしてvarは、その名前空間内で、文字列オブジェクト'Original'の名前になります。そのオブジェクトは2つの名前空間に名前を持ちます。次に、var = 'Changed'varを新しい文字列オブジェクトにバインドするため、メソッドの名前空間は'Original'を忘れます。最後に、その名前空間は忘れられていて、それと共に文字列'Changed'があります。

227

参照渡しではなく/値渡しで 代入で 渡されることを考えてください。そのようにして、あなたが通常の課題の間に何が起こるかをあなたが理解する限り、何が起こっているのかは、常に明らかです。

そのため、リストを関数/メソッドに渡すと、そのリストはパラメータ名に割り当てられます。リストに追加すると、リストが変更されます。リストを再割り当てする inside 関数は元のリストを変更しません。

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

不変型は変更できないので、値で渡されるのと同じように 一見 になります。つまり、intを関数に渡すということは、intをfunctionsパラメータに割り当てるということです。あなたはこれを再割り当てすることしかできませんが、元の変数の値は変わりません。

152
Daren Thomas

Effbot(別名Fredrik Lundh)は、Pythonの変数渡しスタイルをオブジェクトによる呼び出しとして説明しています。 http://effbot.org/zone/call-by-object.htm

オブジェクトはヒープ上に割り当てられ、それらへのポインタはどこにでも渡すことができます。

  • x = 1000のような代入をすると、現在の名前空間の文字列 "x"を1000を含む整数オブジェクトへのポインタにマップする辞書エントリが作成されます。

  • "x"をx = 2000で更新すると、新しい整数オブジェクトが作成され、辞書は新しいオブジェクトを指すように更新されます。古い1000個のオブジェクトは変更されていません(そして、他の何かがオブジェクトを参照しているかどうかに応じて生きているかどうかによって異なります)。

  • y = xのような新しい代入をすると、 "x"のエントリと同じオブジェクトを指す新しい辞書エントリ "y"が作成されます。

  • 文字列や整数のようなオブジェクトは 不変 です。これは単に、作成後にオブジェクトを変更できるメソッドがないことを意味します。例えば、いったん整数オブジェクト1000が作成されると、それは決して変更されません。数学は新しい整数オブジェクトを作成することによって行われます。

  • リストのようなオブジェクトは 可変 です。これは、オブジェクトを指すものなら何でもオブジェクトの内容を変更できることを意味します。たとえば、x = []; y = x; x.append(10); print y[10]を出力します。空のリストが作成されました。 "x"と "y"の両方が同じリストを指しています。 append メソッドはリストオブジェクトを変更(更新)し(データベースへのレコードの追加など)、結果は "x"と "y"の両方に表示されます(データベースの更新がすべてのユーザーに表示されるのと同じです)。そのデータベースへの接続)。

それがあなたのための問題を明確にすることを願っています。

59

技術的には、 Pythonは常に参照値渡し を使用します。 私の他の答え 私のステートメントを支持するために/を繰り返します。

Pythonは常に参照渡しの値を使用します。例外はありません。変数の代入はすべて、参照値をコピーすることを意味します。例外なし。任意の変数は、参照値にバインドされた名前です。常に。

参照値は、ターゲットオブジェクトのアドレスとして考えることができます。アドレスは使用時に自動的に間接参照されます。このように、参照値を使って作業すると、ターゲットオブジェクトを直接操作しているように見えます。しかし、その間には常に参照があり、ターゲットにジャンプするためのもう1つのステップがあります。

これがPythonが参照渡しを使用していることを証明する例です。

Illustrated example of passing the argument

引数が値渡しされた場合、外側のlstは変更できませんでした。緑はターゲットオブジェクト(黒は内部に格納されている値、赤はオブジェクトタイプ)、黄色は内部に参照値を持つメモリです。矢印として描かれています。青い実線の矢印は、(破線の青い矢印の経路を介して)関数に渡された参照値です。醜い濃い黄色は内部辞書です。 (実際には緑色の楕円として描くこともできます。色と形は内部的なものでしかありません。)

id() 組み込み関数を使用して、参照値が何であるか(つまり、ターゲットオブジェクトのアドレス)を知ることができます。

コンパイル言語では、変数はその型の値を取り込むことができるメモリ空間です。 Pythonでは、変数は、ターゲットオブジェクトへの参照値を保持する参照変数にバインドされた名前です(内部的には文字列としてキャプチャされます)。変数の名前は内部辞書のキーであり、その辞書項目の値部分はターゲットへの参照値を格納します。

参照値はPythonでは隠されています。参照値を格納するための明示的なユーザータイプはありません。ただし、リスト要素(または他の適切なコンテナー型の要素)を参照変数として使用できます。これは、すべてのコンテナーがその要素をターゲットオブジェクトへの参照としても格納するためです。言い換えれば、要素は実際にはコンテナの中に含まれていません - 要素への参照だけが含まれています。

57
pepr

私が普段使用している簡単なトリックは、単にそれをリストに入れることです。

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

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

(ええ、これは不便なことがあることを知っていますが、時にはそれを行うのに十分簡単なこともあります。)

41
AmanicA

Pythonには変数はありません

パラメータの受け渡しを理解するための鍵は、「変数」について考えるのをやめることです。 Pythonには名前とオブジェクトがあり、それらが一緒になって変数のように見えますが、3つを常に区別することは有用です。

  1. Pythonには名前とオブジェクトがあります。
  2. 代入は名前をオブジェクトに結び付ける。
  3. 関数に引数を渡すと、名前(関数のパラメータ名)もオブジェクトにバインドされます。

それだけです。可変性はこの質問には無関係です。

例:

a = 1

これは名前aを値1を保持する整数型のオブジェクトに束縛します。

b = x

これは、名前bを、名前xが現在バインドされているのと同じオブジェクトにバインドします。その後、bという名前はxという名前とは無関係になります。

Python 3言語リファレンスのセクション 3.1 および 4.2 を参照してください。

質問の例の読み方

質問に示されているコードでは、ステートメントself.Change(self.variable)は、名前varを(関数Changeのスコープ内で)値'Original'を保持するオブジェクトにバインドし、代入var = 'Changed'(関数Changeの本体内)は、同じ名前を再び割り当てます。他のオブジェクト(文字列を保持することもありますが、まったく別のものになる可能性があります)。

参照渡し方法

(編集2019-04-28)

あなたが変更したいものが変更可能なオブジェクトであるならば、すべてが事実上参照によって渡されるので、問題はありません。

もしそれが immutable object(例えば、bool、number、string)ならば、それを可変オブジェクトでラップすることです。
これに対する素早い解決策は、1要素リストです(self.variableの代わりに、[self.variable]を渡し、関数modify var[0]を使用)。
もっと Pythonic のアプローチは、簡単な、1属性のクラスを紹介することです。この関数はクラスのインスタンスを受け取り、その属性を操作します。

36
Lutz Prechelt

(編集 - ブレアは彼の非常にポピュラーな答えをそれが今正確であるように更新しました)

私は、(Blair Conradによる)最も投票数の多い現在の投稿は、その結果に関しては正しいものの、誤解を招くものであり、その定義に基づいて境界線が正しくないことに注意することが重要です。ユーザーが参照渡しまたは値渡しを許可する言語は多数ありますが(Cのように)、Pythonはそのうちの1つではありません。

David Cournapeauの答えは本当の答えを指し示し、なぜBlair Conradの投稿の振る舞いが正しいように見えるのか、定義が正しくないように見えるのかを説明しています。

Pythonが値渡しである限り、何らかのデータ(「値」でも「参照」でも)を送信する必要があるので、すべての言語は値渡しです。しかし、それはCプログラマーが考えるという意味でPythonが値渡しであるという意味ではありません。

あなたがその振る舞いをしたいのなら、Blair Conradの答えは大丈夫です。しかし、なぜPythonが値渡しでも参照渡しでもないのかということの本質を知りたいのなら、David Cournapeauの答えを読んでください。

35
KobeJohn

本当に良い答えがここにあります。

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

この場合、メソッドvar内のChangeという名前の変数にself.variableへの参照が割り当てられ、すぐにvarに文字列が割り当てられます。もはやself.variableを指していません。次のコードスニペットは、varself.variableが指すデータ構造、この場合はリストを変更するとどうなるかを示しています。

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

他の誰かがこれをさらに明確にすることができると確信しています。

17
Mike Mazur

Pythonの代入による受け渡し方式は、C++の参照パラメータオプションとまったく同じではありませんが、実際にはC言語(およびその他のもの)の引数渡しモデルと非常によく似ています。

  • 不変の引数は効果的に“ by value ”で渡されます。整数や文字列などのオブジェクトはコピーではなくオブジェクト参照で渡されますが、不変オブジェクトをその場で変更することはできません。コピーします。
  • 可変引数は効果的に " by pointer "で渡されます。リストや辞書などのオブジェクトもオブジェクト参照によって渡されます。これは、Cが配列をポインタとして渡す方法と似ています。 C配列によく似ています。
16
ajknzhol

あなたが言うことができるようにあなたが可変オブジェクトを持つ必要がある、しかし私があなたを助けるか、あるいはこの種の問題を解決することさえできるので大域変数をチェックすることをあなたに提案しましょう!

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

例:

>>> 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
15
Nuno Aniceto

ここに答えの多くの洞察力が、私は追加のポイントが明確にここに明確に言及されていないと思います。 pythonのドキュメントからの引用 https://docs.python.org/2/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

「Pythonでは、関数内でのみ参照される変数は暗黙的にグローバルです。変数に関数本体内の任意の場所で新しい値が代入されると、ローカル変数と見なされます。変数に関数内で新しい値が代入されると変数は暗黙的にローカルなので、明示的に 'global'として宣言する必要があります最初に少し驚くべきことですが、割り当てられた変数にglobalを要求すると、意図しない副作用を防ぐことができます。一方、すべてのグローバル参照にglobalが必要な場合は、常にglobalを使用することになり、組み込み関数またはインポートされたモジュールのコンポーネントへの参照をすべてglobalとして宣言する必要があります。副作用を特定するための世界的な宣言の有用性を無効にするだろう」と述べた。

可変オブジェクトを関数に渡すときでも、これは適用されます。そして、私には、オブジェクトへの代入と関数内でのオブジェクトへの操作の間の振る舞いの違いの理由をはっきり説明します。

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)

を与えます:

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

したがって、globalと宣言されていないグローバル変数への代入は、新しいローカルオブジェクトを作成し、元のオブジェクトへのリンクを解除します。

13
Joop

これがPythonで使われているpass by objectという概念の簡単な(私が願っている)説明です。
オブジェクトを関数に渡すときはいつでも、そのオブジェクトへの参照ではなく、オブジェクト自体が渡されます(Pythonのオブジェクトは実際には他のプログラミング言語の値と呼ばれるものです)。言い換えれば、あなたが呼び出すとき:

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

my_list = [0, 1]
change_me(my_list)

実際のオブジェクト - [0、1](他のプログラミング言語では値と呼ばれます)が渡されています。そのため、実際には関数change_meは次のようなことを試みます。

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

これは明らかに関数に渡されるオブジェクトを変更しません。関数がこんな感じだったら:

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

その後、呼び出しは以下のようになります。

[0, 1].append(2)

これは明らかにオブジェクトを変更します。 この答え よく説明しています。

9
matino

Pythonでこの機能がどのように機能するかについてのすばらしい説明以外に、この問題に対する簡単な提案はありません。オブジェクトやインスタンスを作成するように見えるので、インスタンス変数を処理し変更するPythonicの方法は次のとおりです。

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

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

インスタンスメソッドでは、通常、インスタンス属性にアクセスするためにselfを参照します。インスタンス属性を__init__に設定し、それらをインスタンスメソッドで読み込んだり変更したりするのは普通のことです。 selfalsをdef Changeの最初の引数に渡すのもそのためです。

もう1つの解決策は、このような静的メソッドを作成することです。

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
8
Dolf Andringa

たとえ言語がそれを可能にしないとしても、参照によってオブジェクトを渡すための少しトリックがあります。これはJavaでも動作します。1つの項目を含むリストです。 ;-)

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

それは醜いハックですが、うまくいきます。 ;-P

6
itmuckel

次の方法を使って、いくつかのFortranコードを素早くPythonに変換しました。確かに、元の質問が提起されたので参照渡しではありませんが、場合によっては簡単な回避策です。

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
4
Brad Porter

pythonが値とそれらへの参照を処理する方法を考えると、あなたが任意のインスタンス属性を参照することができる唯一の方法は名前によるものです:

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

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

実際のコードでは、もちろん、辞書検索でエラーチェックを追加します。

3
mARK bLOORE

参照渡しはpythonにうまく適合するものではなく、めったに使用すべきではありませんが、現在ローカル変数に割り当てられているオブジェクトを取得したり、呼び出された関数内からローカル変数を再割り当てしたりするための回避策があります。

基本的な考え方は、そのようなアクセスを実行でき、オブジェクトとして他の関数に渡すことができる、またはクラスに格納できる関数を持つことです。

1つの方法は、ラッパー関数でglobal(グローバル変数用)またはnonlocal(関数内のローカル変数用)を使用することです。

def change(wrapper):
    wrapper(7)

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

同じ考えは、変数を読んでdeletingするためにも働きます。

ただ読むためには、呼び出したときにxの現在の値を返すcallableを返すlambda: xを使うより短い方法さえあります。これは、以前の言語で使用されていた「名前による呼び出し」に少し似ています。

変数にアクセスするために3つのラッパーを渡すのは少し面倒ですので、それらをプロキシー属性を持つクラスにラップすることができます。

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の "リフレクション"サポートにより、与えられたスコープ内の名前/変数をそのスコープ内で明示的に定義しなくても再割り当てできるオブジェクトを取得することが可能になります。

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)

ここではByRefクラスが辞書へのアクセスをラップしています。そのため、wrappedへの属性アクセスは、渡された辞書内のアイテムアクセスに変換されます。組み込みのlocalsの結果とローカル変数の名前を渡すことで、ローカル変数にアクセスすることになります。 3.5のPythonドキュメントは辞書の変更はうまくいかないかもしれませんが私にはうまくいくようです。

3
textshell

Pythonの参照渡しは、C++/Javaの参照渡しの概念とはまったく異なります。

  • Java: すべて参照されているので、呼び出された関数のパラメータに加えられたすべての変更は呼び出し元に表示されます。
  • C++: 参照渡しまたは値渡しの両方を使用できます。パラメータが参照渡しの場合は、パラメータがconstとして渡されたかどうかに応じて、変更することもできないこともできます。ただし、constかどうかに関係なく、このパラメータはオブジェクトへの参照を保持しているため、呼び出された関数内で別のオブジェクトを指すように参照を割り当てることはできません。
  • Python: Pythonは「オブジェクト参照渡し」であり、「オブジェクト参照は値渡しされる」とよく言われます。[ここを読む] 1 。呼び出し元と関数の両方が同じオブジェクトを参照していますが、関数内のパラメーターは呼び出し元のオブジェクトのコピーを保持している新しい変数です。 C++と同様に、パラメータは変更することも機能しないこともできます - これは渡されるオブジェクトの種類によって異なります。例えば;不変オブジェクト型は呼び出された関数では変更できませんが、可変オブジェクトは更新または再初期化できます。変更可能な変数の更新または再割り当て/再初期化の大きな違いは、更新された値が呼び出された関数に反映されるのに対して、再初期化された値は反映されないことです。可変オブジェクトへの新しいオブジェクトの代入の範囲はpythonの関数に対してローカルです。 @ blair-conradが提供する例は、これを理解するのに最適です。
2
Alok Garg

あなたの例はたまたまオブジェクト指向であるので、あなたは同様の結果を達成するために以下の変更を加えることができました:

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'
2
Jesse Hogan

辞書は参照によって渡されるので、辞書変数を使用してその内部に参照値を格納できます。

# 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
0
Liakos

それはどこからも言及されていないようであるので、例えばから知られているように参照をシミュレートするためのアプローチ。 C++は "update"関数を使って、実際の変数の代わりにそれを渡します(あるいは "name")。

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

これは、「更新専用スレッドをマルチスレッド処理を安全にすることによって」「アウトオンリー参照」または複数のスレッド/プロセスがある状況で主に役立ちます。

明らかに上記は 読み取り - 値を許可せず、それを更新するだけです。

0
Daniel Jour

内部的にオブジェクト属性はインスタンスディクショナリに格納されているため、参照オブジェクトを格納するためのインスタンスとして単に 空のクラス を使用することができます。例を見てください。

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)
0
sergzach