39316


基本的な質問になります。

GitHubから以下のコードを見つけました。  
<https://gist.github.com/ria3100/fc7ebf6c5d37357919f2>

どうもN-1回同じ処理を反復しているようです。  
なぜこのコードで反復処理がなされているのかが分かりません。

また、

[code]

    temp[len(temp[:])//2] = 1
    
[/code]

がどのような構文かも理解できていません。

文法的なことですが調べきれずにおります。  
お手数ですがお教えいただけないでしょうか。

[code]

    input1 = txt_input[0].split()
    def reversal(temp):
        temp[len(temp[:])//2] = 1
        return temp
    
    def calc(N, temp = [0]):
        print("calc")
        if N == 1:
            return temp
        else:
            ret = temp[:]
            ret.append(0)
            ret.extend(reversal(temp[:]))
            return calc(N-1, ret)
    
    if __name__ == '__main__':
        N = int(input1[0])
        print(calc(N))
    
[/code]


CC BY-SA 3.0
2017-11-05T17:16:41.030
39315
2017-11-06T22:39:21.687
2017-11-05T19:07:52.773
2376
21201
question
python3
GitHubからのコードですが、なぜ反復処理されているかがわかりません


### 反復の要因

`calc()` 関数が最後の行で再帰呼び出ししてます。

[code]

    def calc(N, temp = [0]):
        ...
            return calc(N-1, ret) # 関数の中で同じ関数を使う（再帰呼び出し）
    
[/code]

### リストの構文

`temp[len(temp[:])//2] = 1` は 4 つの処理をしてます。

  1. `temp[:]`: リスト`temp`のコピーを作成
  2. `len(...)`: リストの要素数を取得
  3. `... // 2`: 割り算。ふつうの割り算は`/`ですが、`//`を使うと小数点以下を切り捨てます
  4. `temp[...] = 1`: リスト`temp`の（処理1〜3で算出した）指定のインデックスに`1`を代入

リストには `alist[2:]`（要素の3番目から最後までを取得） のような構文の「スライス」という機能があり、`alist[:]`
は全要素を指定することでリストの新しいコピーを得られます。この場合、`temp`
リストの要素数をわざわざコピーから取得する意味はないように見えますが、リストは可変で要素数は変化するので、期待するタイミングでリストの現在の状態を取る前にリストが変更される恐れがあるような場合はこのようにコピーを取ることがあります（なお、[最新のリビジョン](https://gist.github.com/ria3100/fc7ebf6c5d37357919f2/6957b760898e17be5f77acb72e17c82e042e8320)
では直接サイズを取っています）。

### `1`の代入の意味

このコードでは `1` は山折りを表現しています。リポジトリのコメントに、

> 最初の折り目が谷  
>  それ以降、再帰処理で (N-1) + (最初の谷折り) ＋ (N-1の中央を山折りにしたもの) が出力される

とあり、`temp[len(temp[:])//2] = 1` は「N-1の中央を山折りにしたもの」をプログラミングしていると思われます。

### 参考情報

「[Python チュートリアル](https://docs.python.jp/3/tutorial/index.html)」の次の項目を読んでください。

  * [3.1.1. 数](https://docs.python.jp/3/tutorial/introduction.html#numbers)
  * [3.1.3. リスト型 (list)](https://docs.python.jp/3/tutorial/introduction.html#lists)

関数の再帰については触れられているものがないのですが、できます。関数の定義中に（ヘッダで関数の名前だけでも宣言されていないのに）なぜその関数が使えるのか、という話は長くなるので控えます。

* * *

### おまけ

引数は変数と異なり、外から渡された値を内部名で参照するだけで、代入ができません。しかし Python
では引数に代入しているように見えるコードが書けてしまいます。

[code]

    def func(n = 0):
        if n == 0:
            n = 1 # 引数`n`に`1`を代入したから次の実行で`ok`が出力されるかな？
            func()
        else:
            print("ok.")
    
    func() # 無限ループでエラー！
    
[/code]

上記コードはエラーになります。  
Python では引数と同名の変数を関数内で宣言できるので、`if ...` の中の `n = 1` は引数への代入ではなく変数 `n`
の宣言になります。この変数は `if ...` 〜 `else:` の間でだけ使用でき、引数の `n` より優先されます。  
代入できない引数の `n` は初期値のまま `0` なので、いつになっても `n == 0` が真となり `func()` が繰り返し実行されつづけます。

このように、変数と引数は指すものが異なります。基本的な知識を得るには「[Python
チュートリアル](https://docs.python.jp/3/tutorial/index.html)」を通して実践するのをおすすめします。


CC BY-SA 3.0
2017-11-05T21:53:26.203
39316
2017-11-06T22:39:21.687
2017-11-06T22:39:21.687
39315
answer