PythonでAI。よくある文法、例『(x_train, y_train), (x_test, y_test) = cifar10.load_data()』。

#目的
深層学習とかのAIをPythonで実行する場合、
サンプルコードをそのまま使えば、それなりに動かすことができるが、
ある程度、文法を理解しておかないと、変更等で手間取る場合がある。
実績のあるコードをベースに文法を整理する。

以下のgithubのコードをサンプルとする。
https://github.com/keras-team/keras
cifar10_cnn.py

#関数の戻り値が複数ある。代入文で複数の変数に代入している。

##対象コード
データのロードで、非常に頻繁にみかけるコード。

```
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
```




##ポイント１
**関数の戻り値が複数ある**
ちなみに、関数側のretrunは、以下のようになっている。

```cifar10.py
      (省略)
    if K.image_data_format() == 'channels_last':
        x_train = x_train.transpose(0, 2, 3, 1)
        x_test = x_test.transpose(0, 2, 3, 1)

    return (x_train, y_train), (x_test, y_test)
```

書籍「入門 Python3」オライリー・ジャパン（2017年2月3日 初版第6刷発行)
には、以下の説明がある。

>**関数は任意の型、任意の個数の入力引数を取り、任意の型、任意の数の結果を出力する。**

一応、上記のような説明になっているが、任意の型と言っているあたりで、個数には意味がないとも言える。

文法という意味で、リファレンスを参照すると、

出典：
https://docs.python.org/ja/3/reference/simple_stmts.html#the-return-statement

>7.6. return 文¶
return_stmt ::=  "return" [expression_list]
return は、関数定義内で構文法的にネストして現れますが、ネストしたクラス定義内には現れません。
式リストがある場合、リストが値評価されます。それ以外の場合は None で置き換えられます。
return を使うと、式リスト (または None) を戻り値として、現在の関数呼び出しから抜け出します。


単に、returnされるのは、**expression_list**と書かれているだけ。

更に、expresion_listは、

出典：
https://docs.python.org/ja/3/reference/expressions.html#grammar-token-expression-list

>6.14. 式のリスト¶
expression_list    ::=  expression ("," expression)* [","]
starred_list       ::=  starred_item ("," starred_item)* [","]
starred_expression ::=  expression | (starred_item ",")* [starred_item]
starred_item       ::=  expression | "*" or_expr
リスト表示や辞書表示の一部になっているものを除き、少なくとも一つのカンマを含む式のリストはタプルになります。 タプルの長さは、リストにある式の数に等しくなります。 式は左から右へ評価されます。


**カンマ区切りならば、タプルである**と書かれている。
よって、ここで例にしたものは、1個のタプルが戻っているということもできると思う。

ちなみに、関数の仕様をhelpでみると以下のとおり。

```
>>> from keras.datasets import cifar10
Using TensorFlow backend.
>>> help(cifar10.load_data)
Help on function load_data in module keras.datasets.cifar10:

load_data()
    Loads CIFAR10 dataset.

    # Returns
        Tuple of Numpy arrays: `(x_train, y_train), (x_test, y_test)`.
>>>
```

上記のタプルがタプルのタプルのことをいっているのか、みたまんまの中身のタプルの
ことをいっているのかは、不明。




##ポイント2
**代入文で複数の値を代入している**

わりとなんでもあり。
（さて、具体的にできない例があれば、、、、別途、明示したい。）


以下のリファレンスでは、代入文は以下のように説明されている。
https://docs.python.org/ja/3.7/reference/simple_stmts.html#assignment-statements

>7.2. 代入文 (assignment statement)¶
代入文は、名前を値に (再) 束縛したり、変更可能なオブジェクトの属性や要素を変更したりするために使われます:
assignment_stmt ::=  (target_list "=")+ (starred_expression | yield_expression)
target_list     ::=  target ("," target)* [","]
target          ::=  identifier
                     | "(" [target_list] ")"
                     | "[" [target_list] "]"
                     | attributeref
                     | subscription
                     | slicing
                     | "*" target
(attributeref, subscription, slicing の構文については プライマリ 節を参照してください。)
代入文は式のリスト (これは単一の式でも、カンマで区切られた式リストでもよく、後者はタプルになることを思い出してください) を評価し、得られた単一の結果オブジェクトをターゲット (target) のリストに対して左から右へと代入してゆきます。
代入はターゲット (リスト) の形式に従って再帰的に行われます。ターゲットが変更可能なオブジェクト (属性参照、添字表記、またはスライス) の一部である場合、この変更可能なオブジェクトは最終的に代入を実行して、その代入が有効な操作であるか判断しなければなりません。代入が不可能な場合には例外を発行することもできます。型ごとにみられる規則や、送出される例外は、そのオブジェクト型定義で与えられています (標準型の階層 節を参照してください).
ターゲットリストは、丸括弧や角括弧で囲まれていてもよく、それに対するオブジェクトの代入は、以下のように再帰的に定義されています。
ターゲットリストのターゲットが1つだけでコンマが続いておらず、任意に丸括弧で囲われている場合、オブジェクトはそのターゲットに代入されます。
そうでない場合: オブジェクトは、ターゲットリストのターゲットと同じ数の要素を持つイテラブルでなければならず、要素は左から右へ対応するターゲットに代入されます。
"星付き"のターゲットと呼ばれる、頭にアスタリスクが一つ付いたターゲットがターゲットリストに一つだけ含まれている場合: オブジェクトはイテラブルで、


以下の**ポケットリファレンス**にわかり易い例が記載されているコードが記載されているので、実行してみる。

　Python Pocket Reference, 5th Edition 
　Python In Your Pocket
　By Mark Lutz 
　Publisher: O'Reilly Media

以下のように器用に代入される。（Python 3.7.2 で実行）

```
>>>
>>> a, *b, c = (1,2,3,4)
>>> a,b,c
(1, [2, 3], 4)
>>> b
[2, 3]
>>>
```

#まとめ
コメントなどあれば、お願いします。