また、pythonには値渡しがないと聞いたのですが、これは参考書が悪いのでしょうか?
サイトのurl:https://www.javadrive.jp/python/userfunc/index3.html
参考書では無く、**そのサイトが悪いです。**Pythonには「参照渡し」は存在せず、すべて「値渡し」です。
4. その他の制御フローツール — Python 3.11 ドキュメント#4.7. 関数を定義する
そうすることで、実引数は__値渡し (call by value)__で関数に渡されることになります (ここでの 値 (value) とは常にオブジェクトへの 参照(reference) をいい、オブジェクトの値そのものではありません) [1]。
[1] 実際には、オブジェクトへの参照渡し (call by object reference) と書けばよいのかもしれません。というのは、変更可能なオブジェクトが渡されると、関数の呼び出し側は、呼び出された側の関数がオブジェクトに行ったどんな変更 (例えばリストに挿入された要素) にも出くわすことになるからです。
「オブジェクトへの参照渡し」は「参照渡し(call by reference)」とは異なり物であり、「値渡し」の一種であることに注意してください。「オブジェクトへの参照渡し」は「共有渡し(call by sharing)」や「オブジェクト渡し(call by object)」や「参照の値渡し」(日本のRubyコミュニティでよく使われる表現)と言われるものと同じ評価戦略になります。なお、「参照渡し」と混同しやすいため、「オブジェクトへの参照渡し」を括弧無しで表現することは誤解を生む原因になりますので注意してください。
それを踏まえて、「参照渡し」とは何かです。
[関数の呼び出し先で変更を行うと、呼び出し元の変数の値も変更される]
これをもうちょっと正確に表現すると、このようになります。
[関数の呼び出し先で変数(仮引数)の値に対して変更を行うと、呼び出し元の変数(実引数)の値も変更される]
そう、変更を行うのは変数の値です。実際に「参照渡し」の例をC++で見てみましょう。
C++
1#include <iostream>
2
3void f(int x) {
4 x = 2;
5}
6
7void g(int &x) {
8 x = 3;
9}
10
11int main() {
12 int x = 1;
13 std::cout << x << std::endl;
14 f(x);
15 std::cout << x << std::endl;
16 g(x);
17 std::cout << x << std::endl;
18 return 0;
19}
関数f
は値渡し、関数g
は参照渡しです。どちらも仮引数に対して代入を行うことで、変数の値そのものを変更しています。f
は元の変数に影響はありませんが、g
は元の変数に影響がでます。これが、値渡しと参照渡しの違いです。
Pythonの場合、変数の値は「オブジェクトへの参照」です。オブジェクトそのものではありません。そして、Pythonには「値渡し」しか存在しません。同じようなコードをPythonでも書いてみましょう。
def f(x):
x = 2
x = 1
print(x)
f(x)
print(x)
関数g
をPythonで表現することは不可能です。なお、次のような例を「参照渡し」と間違った表現をしているサイトがあります。
def h(x):
x[0] = 2
x = [1]
print(x)
h(x)
print(x)
それらのサイトが理解していないことは、x[0] = 2
は変数x
の値を変更しているのでは無いと言うことです。x[0] = 2
は変数x
の値である「オブジェクトへの参照」が指し示すリストオブジェクトを変更しているということです。変数x
の値そのものは何も変更されていません。ですので、この例を持って「参照渡し」と言っているのはプログラミングについてよく知らない素人が何かです。そのような人が書いたサイトを参考にする価値はありません。