幼稚園時代「何組」でしたか?

下記のpythonのプログラムで、
関数plot(data)での引数dataには何が渡されるのでしょうか?
plotが30ミリ秒ごとに呼び出されて、plot関数の中で、変数i
が少しずつ変わっているようですが。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig = plt.figure()
i = 0

def plot(data):
global i
i = (i + 1) % 100
plt.cla()
plt.xlim([-10, 10])
plt.ylim([-10, 10])
t = np.arange(0, 361, 10) * np.pi/180
plt.scatter(np.cos(t)*i*0.1, np.sin(t)*i*0.1)

ani = animation.FuncAnimation(fig, plot, interval=30)
plt.show()

質問者からの補足コメント

  • 0、1、2、3、4、・・・って値が順次plotに渡された場合、
    plot()関数内のglobal iとの関係はどうなるのでしょうか?
    呼び出し毎に、その値がiに代入されるのでしょうか?

    No.1の回答に寄せられた補足コメントです。 補足日時:2017/09/22 20:21

A 回答 (4件)

> 0、1、2、3、4、・・・って値が順次plotに渡された場合、


> plot()関数内のglobal iとの関係はどうなるのでしょうか?

平たく言うと「全く関係ない」ですね。
もう一度言いますが、恐らくplot関数の引数dataは、「ダミー」です。FuncAnimationの引数に取るfuncが一引数以上を取る、と言う「仕様」に合わせてダミーとして持ってるだけで、「実は何もして」いません。
大体、plot関数本体内には全く「data」の文字が無いじゃないですか。

plot関数はそれなりにゴチャゴチャしてるんで分かりづらいかもしれませんが、事実上、こういう関数(と言うかプロシージャ)と同じです。

i = 0

def func(arg):
  global i
  i += 1

上のfuncはargと言う引数を要求してますが、本体内ではargと言う引数は「使ってない」ので、ダミーです。funcがやってるのはグローバル変数iの値を「呼び出しされる」度に増やす「副作用」が主目的で、ダミー変数を与えないと動きません(エラーになる)が、とは言っても「どんな変数を与えようと」全く効果が変わりません。argは「意味のない」引数で、だからこそダミーなんです。

同様に、plot関数もグローバル変数iの値を「呼び出される度に」変更していく、ってのが一つの目的で、でもdataそのものはダミー引数ですよね。あとはmatplotlib.pyplotに対してやっぱり出力用の副作用をちょこちょこ命令出してはいますが、data、と言う引数は本体内の命令にはなんら関与してませんね。
    • good
    • 0
この回答へのお礼

詳しい説明有り難うございました。
やっと理解出来ました。(理解が遅くて申し訳ないです^^;)

お礼日時:2017/09/23 00:07

あー、ちなみに。


どこからこのコード引っ張ってきたのかは知らんですが、確かにあんまPythonらしくない(っつーかグローバル変数必要か?)コードに見えますね。
もし気になるなら、次のように書き直しても効果は全く同じだと思いますよ。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig = plt.figure()

def plot(data):
  i = (data + 1) % 100
  plt.cla()
  plt.xlim([-10, 10])
  plt.ylim([-10, 10])
  t = np.arange(0, 361, 10) * np.pi/180
  plt.scatter(np.cos(t)*i*0.1, np.sin(t)*i*0.1)

ani = animation.FuncAnimation(fig, plot, interval=30)
plt.show()
    • good
    • 0

おっと、筆が滑って書いちゃいましたが、キーワード引数、じゃなくってデフォルト引数、ですね。


順次読み替えて下さい。
    • good
    • 0

インデントが無くなってるんで読みにくいですねぇ。



基本的に、着目すべきはmatplotlibのanimationモジュールの模様です。
かつ、これはPythonの話と言うよりライブラリの話なんで、疑問に思った場合はライブラリの説明見た方が早いんですよ。

コードの最後の方に次のように書かれてますね。

ani = animation.FuncAnimation(fig, plot, interval=30)

ここでFuncAnimationと言うメソッドに関数plotを渡しています。
と言う事は、これは構造的にはFuncAnimationってのは一種の「高階関数」(関数を引数として取り、別のデータにapplyする)として設計されてる事が予想が付きます(この辺がC言語なんかだと物凄くやりづらい事をPythonはヘーキでやってる、って事です)。
と言う事は、ここでplotのdata、ってのが明示されてない以上、FuncAnimationが内部的にゴチャゴチャやってんだろうな、って事が予想付きますね。
そこでFuncAnimationの仕様を見てみます。次のサイトで(英語ですが)解説されてますね。

matplotlib.animation.FuncAnimation:
http://matplotlib.org/api/_as_gen/matplotlib.ani …

「class matplotlib.animation.FuncAnimation(fig, func, frames=None, init_func=None, fargs=None, save_count=None, **kwargs)」

正式にはFuncAnimationってのは結構な引数を取るようになってますが、frames=None以降は(Python勉強してるなら分かるでしょうが)キーワード引数になってるから必須のパラメータではありません。
逆に、figとfuncって2つのパラメータは「必須」で「この順序通りに」与えないといけません。
さっきのコードで言うと

ani = animation.FuncAnimation(fig, plot, interval=30)

のfigとplotってのが仕様によるとfigとfuncの2つである、って事です。今はplotがどう扱われてるのかを知りたいわけで、って事はfuncの項目を見てみましょう。

「func : callable

The function to call at each frame. The first argument will be the next value in frames.」

テキトーな訳は以下の通り。

「func : 呼び出し可能

ここで関数はフレーム毎に呼び出される。第一引数はframes内の次の値となる。」

っつーことは、FuncAnimationのデフォルト引数で、framesの値がいずれにせよ使われてる、って事になるんですが、

ani = animation.FuncAnimation(fig, plot, interval=30)

の中にはそんな引数がありません。framesを与えなくても動作してる、って事は明らかにデフォルト引数が使われてるんだろう、って考えられます。
もうこの辺で、「一体何が与えられるのか」勘が良ければ気づいちゃいますが、いちおうframes引数の説明を見てみますか。

「frames : iterable, int, generator function, or None, optional

Source of data to pass func and each frame of the animation

If an iterable, then simply use the values provided. If the iterable has a length, it will override the save_count kwarg.

If an integer, equivalent to passing range(frames)

If a generator function, then must have the signature

def gen_function() -> obj:

In all of these cases, the values in frames is simply passed through to the user-supplied func and thus can be of any type.

If None, then equivalent to passing itertools.count.」

訳すのメンド臭いんで訳しませんが(笑)、もう一度FuncAnimationの引数を見てみます。

「class matplotlib.animation.FuncAnimation(fig, func, frames=None, init_func=None, fargs=None, save_count=None, **kwargs)」

frames、ってのは「デフォルト引数」です。って事は明示しなければ「Noneが使われる」って事ですね。
従ってFuncAnimationの内部的には、

「If None, then equivalent to passing itertools.count.」

との事なんでitertools.countでの値が使われてる模様です。
itertools自体は次のページで説明されていますね。

itertools — 効率的なループ実行のためのイテレータ生成関数:
https://docs.python.jp/3/library/itertools.html

要するに0、1、2、3、4、・・・って値が順次plotに渡されてる、って事です。
実際問題、plotの定義を見ると、引数dataってのは内部的に全く使われていません。従って、plotに与えるdataはFuncAnimationの仕様を満たすため、ある種のダミー引数なのでは、と言う予想も付きますね。
「pythonでの引数について」の回答画像1
この回答への補足あり
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!