引数は割り当てによって渡されます。この背後にある理論的根拠は2つあります。
- 渡されたパラメータは、実際には、基準オブジェクトへの(しかし、参照は値によって渡されます)
- 一部のデータ型は変更可能ですが、その他は変更できません
そう:
より明確にするために、いくつかの例を挙げましょう。
リスト-可変タイプ
メソッドに渡されたリストを変更してみましょう:
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])
これは少し面倒ですが。