質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

4回答

50017閲覧

pythonってポインタ渡しみたいなことできないんですか?

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

6クリップ

投稿2018/04/19 04:51

関数の引数で関数の外の値を変えたいんですけどできないんですか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

追記: 本件からちょっと外れてしまうかもしれませんが、下手に「値渡し」と書いてしまいお馴染みの混乱を招く結果になってしまったようです。

call by value
call by reference
call by sharing

という用語を使うとするとcall by sharingが一番しっくりきそうに思います。(hayataka2049さんありがとうございます)。pythonだけでなくjavaとかC#(の参照型)とか多くの言語でもお馴染みの評価戦略だと思います。call by valueとずっと捉えてたのですがその用語を使うのは控えてcall by sharingといおうと思いました。

以下の元の回答

参照渡しはできません。常に値渡しです。

変更した値を何らかの変更可能なコンポーネントオブジェクト(listとかdictとか)の要素にしておいて、関数の中でコンポーネントオブジェクトの要素を変更するようにすればまぁポインター渡しっぽいことができなくはないです。

ちなみに固定的な変数なのであれば

  • グローバル変数ならglobal宣言を用いればできます。
  • 外側のローカル変数でもnonlocalを使うとそれができる場面があります。

投稿2018/04/19 04:57

編集2018/04/19 10:15
KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2018/04/19 05:01 編集

値渡しって書くと違う解釈されかねないかもです。 def foo(x):  x = something と書いたとき、呼び出し元のなんらかの変数に影響を及ぼさないという意味で値渡しと書いてます。
退会済みユーザー

退会済みユーザー

2018/04/19 05:04 編集

nonlocal調べてみたら面白そうでした。ありがとうございます。
KSwordOfHaste

2018/04/19 05:08 編集

個人的にはLouiS0616さん回答の方のお奨めの順がよいと思います。nonlocalは乱用するとglobalよりひどいかも?自分はnonlocalってなんだろうと思って試しはしましたが、普段そういうふうな作りは避けようとする方です。
hayataka2049

2018/04/19 05:10

「すべて値渡し」派と「すべて参照渡し」派がいて、何も知らない人が見ると混乱しそうですw
LouiS0616

2018/04/19 05:15

平和主義者ですが『参照の値渡しは参照渡しと呼んでよい。だって似たようなもんじゃん。』という派閥には容赦なく殴り掛かるようにしています。
KSwordOfHaste

2018/04/19 05:17 編集

そう思います。qiitaとか見ても結構「???」な記事を見かけます。 自分はC++のfoo(int& a)とかVBのfoo(ByRef a as Integer)みたいなものが参照渡しだと思っております。 a=1 って書くと呼び出し元の変数が書き換わるケースのみ参照渡しと思うことにしてます。 ---追記--- 「そう思います」は殴りかかるという意味ではないです!「混乱しそうです」の方への意見ですw;
hayataka2049

2018/04/19 05:21

あ、LouiS0616さんはポインタ渡し(みたいなもん)って書いてました・・・私も参照渡しという言葉は使ってなかったので、前言撤回しておきます
KSwordOfHaste

2018/04/19 05:28

質問意図が「外側のスコープの変数の値を書き換える」というものに見えたので参照渡しという単語を使いました。使わなくてもよかったかもです。 --- 余談ですが、最近gc.get_referrersについての質問があってそれに大変興味を魅かれて調べてたのですがクロージャーを作るとcellオブジェクトというのが出てきまして、それがなんとなくインタープリタの内部で参照渡しっぽいメカニズムの実装に使われているのではと想像しました。本当かどうかはわかりません。
YouheiSakurai

2018/04/19 08:28

「ん?結局どっち?」と困惑中です。疑いなく全部参照渡しだと思ってました。def func(x)に対してfunc(1)と呼んでも、xには1への参照が渡されると理解してました。殴られる側?
KSwordOfHaste

2018/04/19 08:42

自分は値渡しだと思ってます。pythonのvalueは全てがオブジェクトですが、変数へ代入したり関数の引数へ渡す際に一々内容をコピーしていたのではナンセンスなので、オブジェクトを扱う際には全てオブジェクトの実体の参照をvalueとして扱うことになっていると捉えます。C#でもjavaでもrubyでもオブジェクトを扱う言語では一般的といってよい考え方と思います。 しかしそのことを参照渡しといってしまうとC++プログラマーやVBプログラマーがいう「参照渡し」と違うものであり混乱するのは必至です。そこで自分は参照わたしとは呼ばないことにしてます。参照渡しって計算機言語機能についての一般の用語だと思うのですが「オブジェクトのアドレスを値として扱うこと」とは別の概念(呼び出された方が変数を変更すると呼び出した側が指定した変数の値も書き換わることの方)だと思っています。
hayataka2049

2018/04/19 09:37

いちばん議論の余地がなく、混乱を招かないのはcall by sharing(共有渡し)なんじゃ、と思ったり・・・(単に通じない言葉なだけかも)
YouheiSakurai

2018/04/19 10:00

「Call by sharing」で自分に内包する誤差に気付くことが出来ました。ありがとうございます。(危ない危ない、容赦なく殴られる側だった。)
KSwordOfHaste

2018/04/19 10:05

hayataka2049さんありがとうございます。そうですね!call by sharingといえば一番よかったんですね。自分はcall by sharingってcall by valueの兄弟だと捉えてたのですが用語を分けた方がよさそうだと思いました。 しかしじゃぁcall by valueってどこまでのことをいうんでしょうかね。 渡すオブジェクトがimmutableなものだとcall by sharingなんでしょうか、call by valueなんでしょうか><
hayataka2049

2018/04/19 10:11 編集

call by valueはCのアレを連想するのと、そもそも明示的にアドレスやらオブジェクトのidやらが見えてないのに値渡しと呼称するのもどうか? と思います。個人的には。 immutableかmutableかはあまり本質的な問題ではないと思います。単に引数への再代入の取扱の問題なのでは def f1(a: int): ____a = a + 1 def f2(a: list): ____a = a + [1] 何が違うんだよ、と個人的には思うんですけど。
LouiS0616

2018/04/19 10:35 編集

今更ですが、自分の回答の方に『参照渡しに期待する動作』を書き加えました。 Qiitaではしばしば『参照渡し』vs『参照の値渡し』の構図が見られ、なかなか議論が収束していないので、あんまり不用意にネタにしちゃいけなかったかもしれません。反省。
KSwordOfHaste

2018/04/19 10:13

> 値渡しと呼称するのもどうか? と思います。 同意します。回答を訂正してみたのですが、多少ましにしたつもりです。
hayataka2049

2018/04/19 10:44 編集

pythonのような言語の動作を説明しようとすると、恐らく暗黙ポインタ渡しか暗黙アドレス渡しとでも呼称するのが適当と思いますが、この名前は流行らないでしょうねぇ・・・ 追記:潔くポインタ渡しみたいなもの、と呼べば良いのかも・・・
YouheiSakurai

2018/04/19 10:31 編集

プログラミング言語的に考えずに、関数(サブルーチン?)呼び出しのスタックに生の値を乗せるのか否かで値渡しとそれ以外に二分すると、スッキリする気がするんですがねえ。(誰への反論でもない)
KSwordOfHaste

2018/04/19 10:36

> スタックに生の値を乗せるのか否か...スッキリする そうも思えますね。ただ実際に言語システムの内部がどうなっているかわかりにくい(あえて明記されてない)ケースも多いように思えるのでどちらかといえば言語機能的に捉えた方がいいのかなぁというのが自分の意見です。
YouheiSakurai

2018/04/19 10:41

KSwordOfHasteさん、ありがとうございます。異論なしです。
KSwordOfHaste

2018/04/19 10:44

「どうやったらどういう結果になる」は分かってるのに用語で混乱するってことは用語自体を使うのを止した方がいいのかも知れません。少なくとも自分にとってはこの用語は避けた方がよさそうです。色々なご指摘をいただき感謝です。
mkgrei

2018/04/19 12:00 編集

def f0(a: int): ____a += 1 def f1(a: int): ____a = a + 1 def f2(a: list): ____a = a + [1] def f3(a: list): ____a += [1] 最後だけ違う… 浅いコピーと考えることはできるのだろうか。(疑問)
KSwordOfHaste

2018/04/19 12:02

それは元の変数が置き換わったのではなくてlistの中身が変化したのですよね? b = [1, 2];print(id(b));f3(b);print(id(b)) とやればbに違うオブジェクトが代入されたわけではないことがわかるので、自分は def f3(a: MyClass): ____a.member = something とやってるのと同じ意味合いと捉えています。
hayataka2049

2018/04/19 12:11

+=のような複合代入演算子が特殊で、極力in-placeで処理するための代入演算子として定義されてる・・・んじゃなかったでしたっけ? これが導入された経緯自体、numpyでin-placeな代入をしたかったからという話をどこかで読んだ記憶があります。ググっても見つけられなかったのですが・・・
KSwordOfHaste

2018/04/19 12:11

なるほど、call by sharingによる値の変化がcall by referenceじゃないか!と言わせるということですかね。やっぱりcall by valueっていうのは止した方がいいですねw;
mkgrei

2018/04/19 12:26

can110さん +1 浅いコピーの件は忘れてください。 数ヶ月前に同じ勘違いをした記憶があります。 a = [] def f(x): .....# x = a <-コピーではないですね。なんというんでしたっけ…。ただの代入ですか。 f(a)
hayataka2049

2018/04/19 12:37 編集

公式FAQにありましたか。素晴らしい ところで、 >there’s no alias between an argument name in the caller and callee, and so no call-by-reference per se. pythonに参照渡しそれ自体はない、aliasがあるの(PHPのみたいな)が参照渡し、というpythonの公式見解が出ましたので、これで議論の余地がなくなりましたね。素晴らしいことです
mkgrei

2018/04/19 12:42 編集

pass by assignmentでしたね。 うまい言い回しです…
KSwordOfHaste

2018/04/19 12:43

wikiとかでpass by assginmentを探してみてもなさげなのでどこから出てきたんだろうその用語は・・・なんて思ってしまいました。知識不足を痛感します。
guest

0

上から順にお勧めです。

  • 戻り値で結果を返すようにする

気軽に複数の要素を返せますし、Cと違ってうっかりフルコピーしてしまうことがないです。

  • ミュータブルな要素を引数として渡す

状況によってはこちらが自然です。

  • グローバル宣言をして再代入

個人的には禁忌だと思います。『Python global』で調べてください。

なお、

pythonってポインタ渡しみたいなことできないんですか?

もともと全部ポインタ渡しみたいなもんです。
参照値を関数内部で書き換えたときに呼び出し元に影響しないのはCも一緒。

C

1#include <stdio.h> 2 3int the_answer = 42; 4void func(int* arg) { 5 arg = &the_answer; 6 printf("%d\n", *arg); // 42 7} 8 9int main(void) { 10 int var = -1; 11 func(&var); 12 printf("%d\n", var); // -1 13 14 return 0; 15}

Python

1def func(arg): 2 arg = 42 3 print(arg) # 42 4 5var = -1 6func(var) 7print(var) # -1

私が『参照渡し』に期待する動作

C++

1#include<iostream> 2 3void func(int& arg) { 4 arg = 42; 5 std::cout << arg << std::endl; // 42 6} 7 8int main(void) { 9 int val = -1; 10 func(val); 11 std::cout << val << std::endl; // 42 12 13 return 0; 14}

投稿2018/04/19 04:54

編集2018/04/19 10:12
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

もう質問クローズしてますが、余談として。

Pythonのような言語では、参照渡しの存在を気にする必要がないと感じています。
値渡しだけで事が足りてしまうという意味で。

Python

1def update_a_b_c(a, b, c): 2 a = a * something1 3 b = b + something2 4 c = c / something3 5 return (a, b, c)

something はなんかしらの何かなので気にしないでください。
上記のようにreturnで複数の要素を返却できるので、引数経由で値を返す必要がありません。

Python

1a, b, c = update_a_b_c(a, b, c)

受け取り先で上記のように受け取れば、a, b, cをそれぞれ更新できます。

議論からは逸れていますが、考える必要のないものを考えるのも時間がもったいない、と思いまして一筆取った次第。

投稿2018/04/19 05:52

kazto

総合スコア7196

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hayataka2049

2018/04/19 06:04 編集

ときどき例外があるのがいやらしいところです。油断していると「言語仕様にあるもん使って何が悪いの?」とでも言いたげなものに出くわします。 ramdon.shuffleの例 >>> import random >>> lst = list(range(10)) >>> lst [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> random.shuffle(lst) >>> lst [9, 4, 7, 2, 8, 6, 1, 5, 3, 0] あとは、パフォーマンス考えるとnumpy配列の操作をin-placeでやらざるを得ない、みたいなシチュエーションとか・・・気にするときは気にします
kazto

2018/04/19 06:20

random.shuffle、なんていやらしい・・・ numpyは確かにおっしゃる通り。
mkgrei

2018/04/19 10:53

mutable/immutableでまとめてみてはいかがでしょう? from random import shuffle a = (1,2,3,4,5) print(a) shuffle(a) print(a)
hayataka2049

2018/04/19 11:03

immutableにすべきはimmutableにして、in-placeでやられる関数に渡しても例外で止まって事故らないようにするということですか? 確かにそれはそれで安全ですね。
mkgrei

2018/04/19 11:26

それもありますが、値を渡した時に、immutableのポインタを変えることなく中身を変更した時だけスコープから出た時に変更されます。 数字のインクリメントをするような場合、数字のオブジェクトは新たに作られ、変数が指す先が変わってしまうので、変更が反映されないのかと。
guest

0

むしろ逆で、デフォルトでポインタ渡しみたいになっています。それどころか、変数もすべてポインタで実体と結びついていますし。

python

1>>> lst = [] 2>>> def append_lst(lst): 3... lst.append(None) 4... 5>>> lst 6[] 7>>> append_lst(lst) 8>>> lst 9[None]

でもこっちは失敗します。

python

1>>>a = 1 2>>>def add_a(a): 3... a = a + 1 4... 5>>>a 61 7>>>add_a(a) 8>>>a 91

add_aはローカル変数aのポインタが「1」オブジェクトから「2」オブジェクトに張り替えられて終了するだけ。「1」オブジェクトの実体に影響したりはしません。

一応、リストに入れればそれっぽいことはできます。

python

1>>> a = 1 2>>> lst = [a] 3>>> def add_a2(lst): 4... lst[0] = lst[0] + 1 5... 6>>> lst 7[1] 8>>> add_a2(lst) 9>>> lst 10[2]

これは「1」オブジェクトにポインタを張ってるリストを渡して、そのポインタを「2」に張り替える操作をしたんです。

投稿2018/04/19 05:03

hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問