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

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

ただいまの
回答率

90.35%

  • Python

    9102questions

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

  • Python 3.x

    7313questions

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

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

解決済

回答 4

投稿

  • 評価
  • クリップ 4
  • VIEW 3,925

syoshinsha

score 23

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+7

上から順にお勧めです。

  • 戻り値で結果を返すようにする
    気軽に複数の要素を返せますし、Cと違ってうっかりフルコピーしてしまうことがないです。
  • ミュータブルな要素を引数として渡す
    状況によってはこちらが自然です。
  • グローバル宣言をして再代入
    個人的には禁忌だと思います。『Python global』で調べてください。

なお、

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

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

#include <stdio.h>

int the_answer = 42;
void func(int* arg) {
    arg = &the_answer;
    printf("%d\n", *arg);   // 42
}

int main(void) {
    int var = -1;
    func(&var);
    printf("%d\n", var);    // -1

    return 0;
}
def func(arg):
    arg = 42
    print(arg)  # 42

var = -1    
func(var)
print(var)      # -1

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

#include<iostream>

void func(int& arg) {
    arg = 42;
    std::cout << arg << std::endl;  // 42
}

int main(void) {
    int val = -1;
    func(val);
    std::cout << val << std::endl;  // 42

    return 0;
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+6

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

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 14:00 編集

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

    キャンセル

  • 2018/04/19 14:02 編集

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

    キャンセル

  • 2018/04/19 14:07 編集

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

    キャンセル

  • 2018/04/19 14:10

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

    キャンセル

  • 2018/04/19 14:15

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

    キャンセル

  • 2018/04/19 14:16 編集

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

    キャンセル

  • 2018/04/19 14:21

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

    キャンセル

  • 2018/04/19 14:28

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

    キャンセル

  • 2018/04/19 17:28

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

    キャンセル

  • 2018/04/19 17:42

    自分は値渡しだと思ってます。pythonのvalueは全てがオブジェクトですが、変数へ代入したり関数の引数へ渡す際に一々内容をコピーしていたのではナンセンスなので、オブジェクトを扱う際には全てオブジェクトの実体の参照をvalueとして扱うことになっていると捉えます。C#でもjavaでもrubyでもオブジェクトを扱う言語では一般的といってよい考え方と思います。

    しかしそのことを参照渡しといってしまうとC++プログラマーやVBプログラマーがいう「参照渡し」と違うものであり混乱するのは必至です。そこで自分は参照わたしとは呼ばないことにしてます。参照渡しって計算機言語機能についての一般の用語だと思うのですが「オブジェクトのアドレスを値として扱うこと」とは別の概念(呼び出された方が変数を変更すると呼び出した側が指定した変数の値も書き換わることの方)だと思っています。

    キャンセル

  • 2018/04/19 18:37

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

    キャンセル

  • 2018/04/19 19:00

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

    キャンセル

  • 2018/04/19 19:05

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

    キャンセル

  • 2018/04/19 19:09

    難しいですけど、https://en.wikipedia.org/wiki/Evaluation_strategyが良かったです。

    キャンセル

  • 2018/04/19 19:11 編集

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

    def f2(a: list):
    ____a = a + [1]

    何が違うんだよ、と個人的には思うんですけど。

    キャンセル

  • 2018/04/19 19:13 編集

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

    キャンセル

  • 2018/04/19 19:13

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

    キャンセル

  • 2018/04/19 19:17

    いちおうteratail内にもこういう議論はあるんですよね。
    https://teratail.com/questions/84660

    キャンセル

  • 2018/04/19 19:23 編集

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

    キャンセル

  • 2018/04/19 19:30 編集

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

    キャンセル

  • 2018/04/19 19:36

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

    キャンセル

  • 2018/04/19 19:41

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

    キャンセル

  • 2018/04/19 19:44

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

    キャンセル

  • 2018/04/19 20:54 編集

    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]

    最後だけ違う…

    浅いコピーと考えることはできるのだろうか。(疑問)

    キャンセル

  • 2018/04/19 21:02

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

    キャンセル

  • 2018/04/19 21:05 編集

    ですので、浅いコピーのときの振る舞いと似ているな、と思ったのです。(<-修正;誤り)

    https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference

    キャンセル

  • 2018/04/19 21:11

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

    キャンセル

  • 2018/04/19 21:11

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

    キャンセル

  • 2018/04/19 21:20

    あ。この質問、本家のFAQと同じような…
    https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference
    (もちろんこの質問と回答が無意味というわけでは全くありません。私自身勉強になりましたし)

    キャンセル

  • 2018/04/19 21:26

    can110さん +1

    浅いコピーの件は忘れてください。
    数ヶ月前に同じ勘違いをした記憶があります。

    a = []
    def f(x):
    .....# x = a <-コピーではないですね。なんというんでしたっけ…。ただの代入ですか。
    f(a)

    キャンセル

  • 2018/04/19 21:36 編集

    公式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の公式見解が出ましたので、これで議論の余地がなくなりましたね。素晴らしいことです

    キャンセル

  • 2018/04/19 21:41

    >浅いコピーの件は忘れてください。
    mkgreiさんが提示された
    https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference
    から辿って、たまたま見つけただけなのでお気になさらず。

    キャンセル

  • 2018/04/19 21:41 編集

    pass by assignmentでしたね。

    うまい言い回しです…

    キャンセル

  • 2018/04/19 21:43

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

    キャンセル

+3

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

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

def update_a_b_c(a, b, c):
    a = a * something1
    b = b + something2
    c = c / something3
    return (a, b, c)


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

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


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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/19 15:03 編集

    ときどき例外があるのがいやらしいところです。油断していると「言語仕様にあるもん使って何が悪いの?」とでも言いたげなものに出くわします。
    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でやらざるを得ない、みたいなシチュエーションとか・・・気にするときは気にします

    キャンセル

  • 2018/04/19 15:20

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

    キャンセル

  • 2018/04/19 19:53

    mutable/immutableでまとめてみてはいかがでしょう?

    from random import shuffle
    a = (1,2,3,4,5)
    print(a)
    shuffle(a)
    print(a)

    キャンセル

  • 2018/04/19 20:03

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

    キャンセル

  • 2018/04/19 20:26

    それもありますが、値を渡した時に、immutableのポインタを変えることなく中身を変更した時だけスコープから出た時に変更されます。

    数字のインクリメントをするような場合、数字のオブジェクトは新たに作られ、変数が指す先が変わってしまうので、変更が反映されないのかと。

    キャンセル

+2

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

>>> lst = []
>>> def append_lst(lst):
...     lst.append(None)
... 
>>> lst
[]
>>> append_lst(lst)
>>> lst
[None]

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

>>>a = 1
>>>def add_a(a):
...    a = a + 1
...
>>>a
1
>>>add_a(a)
>>>a
1

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

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

>>> a = 1
>>> lst = [a]
>>> def add_a2(lst):
...     lst[0] = lst[0] + 1
... 
>>> lst
[1]
>>> add_a2(lst)
>>> lst
[2]

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • Python

    9102questions

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

  • Python 3.x

    7313questions

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

閲覧数の多いPythonの質問