Pythonのドキュメントでは、パラメータが参照と値のどちらで渡されるかについては不明確で、次のコードでは変更されていない値 'Original'が生成されます。
class PassByReference:
def __init__(self):
self.variable = 'Original'
self.change(self.variable)
print(self.variable)
def change(self, var):
var = 'Changed'
実際の参照によって変数を渡すために私にできることはありますか?
引数は 代入によって渡されます 。この背景にある理論的根拠は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_list
はouter_list
参照のコピーであり、the_list
に新しいリストを指すようにしましたが、outer_list
が指す場所を変更する方法はありませんでした。
不変なので、文字列の内容を変更するためにできることは何もありません
それでは、参照を変更してみましょう
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_string
はouter_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])
これは少し面倒なようですが。
問題は、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'
値渡しでも参照渡しでもありません。オブジェクト呼び出しです。 Fredrik Lundhによるこれを参照してください。
http://effbot.org/zone/call-by-object.htm
これは重要な引用です:
「... variables [names]はnotオブジェクトです。他の変数で表すことも、オブジェクトで参照することもできません。」
あなたの例では、Change
メソッドが呼び出されると、 - 名前空間 がそれに対して作成されます。そしてvar
は、その名前空間内で、文字列オブジェクト'Original'
の名前になります。そのオブジェクトは2つの名前空間に名前を持ちます。次に、var = 'Changed'
はvar
を新しい文字列オブジェクトにバインドするため、メソッドの名前空間は'Original'
を忘れます。最後に、その名前空間は忘れられていて、それと共に文字列'Changed'
があります。
参照渡しではなく/値渡しで 代入で 渡されることを考えてください。そのようにして、あなたが通常の課題の間に何が起こるかをあなたが理解する限り、何が起こっているのかは、常に明らかです。
そのため、リストを関数/メソッドに渡すと、そのリストはパラメータ名に割り当てられます。リストに追加すると、リストが変更されます。リストを再割り当てする 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パラメータに割り当てるということです。あなたはこれを再割り当てすることしかできませんが、元の変数の値は変わりません。
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"の両方に表示されます(データベースの更新がすべてのユーザーに表示されるのと同じです)。そのデータベースへの接続)。
それがあなたのための問題を明確にすることを願っています。
技術的には、 Pythonは常に参照値渡し を使用します。 私の他の答え 私のステートメントを支持するために/を繰り返します。
Pythonは常に参照渡しの値を使用します。例外はありません。変数の代入はすべて、参照値をコピーすることを意味します。例外なし。任意の変数は、参照値にバインドされた名前です。常に。
参照値は、ターゲットオブジェクトのアドレスとして考えることができます。アドレスは使用時に自動的に間接参照されます。このように、参照値を使って作業すると、ターゲットオブジェクトを直接操作しているように見えます。しかし、その間には常に参照があり、ターゲットにジャンプするためのもう1つのステップがあります。
これがPythonが参照渡しを使用していることを証明する例です。
引数が値渡しされた場合、外側のlst
は変更できませんでした。緑はターゲットオブジェクト(黒は内部に格納されている値、赤はオブジェクトタイプ)、黄色は内部に参照値を持つメモリです。矢印として描かれています。青い実線の矢印は、(破線の青い矢印の経路を介して)関数に渡された参照値です。醜い濃い黄色は内部辞書です。 (実際には緑色の楕円として描くこともできます。色と形は内部的なものでしかありません。)
id()
組み込み関数を使用して、参照値が何であるか(つまり、ターゲットオブジェクトのアドレス)を知ることができます。
コンパイル言語では、変数はその型の値を取り込むことができるメモリ空間です。 Pythonでは、変数は、ターゲットオブジェクトへの参照値を保持する参照変数にバインドされた名前です(内部的には文字列としてキャプチャされます)。変数の名前は内部辞書のキーであり、その辞書項目の値部分はターゲットへの参照値を格納します。
参照値はPythonでは隠されています。参照値を格納するための明示的なユーザータイプはありません。ただし、リスト要素(または他の適切なコンテナー型の要素)を参照変数として使用できます。これは、すべてのコンテナーがその要素をターゲットオブジェクトへの参照としても格納するためです。言い換えれば、要素は実際にはコンテナの中に含まれていません - 要素への参照だけが含まれています。
私が普段使用している簡単なトリックは、単にそれをリストに入れることです。
def Change(self, var):
var[0] = 'Changed'
variable = ['Original']
self.Change(variable)
print variable[0]
(ええ、これは不便なことがあることを知っていますが、時にはそれを行うのに十分簡単なこともあります。)
パラメータの受け渡しを理解するための鍵は、「変数」について考えるのをやめることです。 Pythonには名前とオブジェクトがあり、それらが一緒になって変数のように見えますが、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属性のクラスを紹介することです。この関数はクラスのインスタンスを受け取り、その属性を操作します。
(編集 - ブレアは彼の非常にポピュラーな答えをそれが今正確であるように更新しました)
私は、(Blair Conradによる)最も投票数の多い現在の投稿は、その結果に関しては正しいものの、誤解を招くものであり、その定義に基づいて境界線が正しくないことに注意することが重要です。ユーザーが参照渡しまたは値渡しを許可する言語は多数ありますが(Cのように)、Pythonはそのうちの1つではありません。
David Cournapeauの答えは本当の答えを指し示し、なぜBlair Conradの投稿の振る舞いが正しいように見えるのか、定義が正しくないように見えるのかを説明しています。
Pythonが値渡しである限り、何らかのデータ(「値」でも「参照」でも)を送信する必要があるので、すべての言語は値渡しです。しかし、それはCプログラマーが考えるという意味でPythonが値渡しであるという意味ではありません。
あなたがその振る舞いをしたいのなら、Blair Conradの答えは大丈夫です。しかし、なぜPythonが値渡しでも参照渡しでもないのかということの本質を知りたいのなら、David Cournapeauの答えを読んでください。
本当に良い答えがここにあります。
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' )
この場合、メソッドvar
内のChange
という名前の変数にself.variable
への参照が割り当てられ、すぐにvar
に文字列が割り当てられます。もはやself.variable
を指していません。次のコードスニペットは、var
とself.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']
>>>
他の誰かがこれをさらに明確にすることができると確信しています。
Pythonの代入による受け渡し方式は、C++の参照パラメータオプションとまったく同じではありませんが、実際にはC言語(およびその他のもの)の引数渡しモデルと非常によく似ています。
あなたが言うことができるようにあなたが可変オブジェクトを持つ必要がある、しかし私があなたを助けるか、あるいはこの種の問題を解決することさえできるので大域変数をチェックすることをあなたに提案しましょう!
例:
>>> 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
ここに答えの多くの洞察力が、私は追加のポイントが明確にここに明確に言及されていないと思います。 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と宣言されていないグローバル変数への代入は、新しいローカルオブジェクトを作成し、元のオブジェクトへのリンクを解除します。
これが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)
これは明らかにオブジェクトを変更します。 この答え よく説明しています。
Pythonでこの機能がどのように機能するかについてのすばらしい説明以外に、この問題に対する簡単な提案はありません。オブジェクトやインスタンスを作成するように見えるので、インスタンス変数を処理し変更するPythonicの方法は次のとおりです。
class PassByReference:
def __init__(self):
self.variable = 'Original'
self.Change()
print self.variable
def Change(self):
self.variable = 'Changed'
インスタンスメソッドでは、通常、インスタンス属性にアクセスするためにself
を参照します。インスタンス属性を__init__
に設定し、それらをインスタンスメソッドで読み込んだり変更したりするのは普通のことです。 self
alsを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
たとえ言語がそれを可能にしないとしても、参照によってオブジェクトを渡すための少しトリックがあります。これは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
次の方法を使って、いくつかの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
pythonが値とそれらへの参照を処理する方法を考えると、あなたが任意のインスタンス属性を参照することができる唯一の方法は名前によるものです:
class PassByReferenceIsh:
def __init__(self):
self.variable = 'Original'
self.change('variable')
print self.variable
def change(self, var):
self.__dict__[var] = 'Changed'
実際のコードでは、もちろん、辞書検索でエラーチェックを追加します。
参照渡しはpythonにうまく適合するものではなく、めったに使用すべきではありませんが、現在ローカル変数に割り当てられているオブジェクトを取得したり、呼び出された関数内からローカル変数を再割り当てしたりするための回避策があります。
基本的な考え方は、そのようなアクセスを実行でき、オブジェクトとして他の関数に渡すことができる、またはクラスに格納できる関数を持つことです。
1つの方法は、ラッパー関数でglobal
(グローバル変数用)またはnonlocal
(関数内のローカル変数用)を使用することです。
def change(wrapper):
wrapper(7)
x = 5
def setter(val):
global x
x = val
print(x)
同じ考えは、変数を読んでdel
etingするためにも働きます。
ただ読むためには、呼び出したときに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ドキュメントは辞書の変更はうまくいかないかもしれませんが私にはうまくいくようです。
Pythonの参照渡しは、C++/Javaの参照渡しの概念とはまったく異なります。
あなたの例はたまたまオブジェクト指向であるので、あなたは同様の結果を達成するために以下の変更を加えることができました:
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'
辞書は参照によって渡されるので、辞書変数を使用してその内部に参照値を格納できます。
# 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
それはどこからも言及されていないようであるので、例えばから知られているように参照をシミュレートするためのアプローチ。 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
これは、「更新専用スレッドをマルチスレッド処理を安全にすることによって」「アウトオンリー参照」または複数のスレッド/プロセスがある状況で主に役立ちます。
明らかに上記は 読み取り - 値を許可せず、それを更新するだけです。
内部的にオブジェクト属性はインスタンスディクショナリに格納されているため、参照オブジェクトを格納するためのインスタンスとして単に 空のクラス を使用することができます。例を見てください。
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)