Python 1本うどんコード

# はじめに
Pythonには[リスト内包表記](https://docs.python.org/ja/3.8/tutorial/datastructures.html#list-comprehensions)という便利な記法があります。リスト内包表記の記法は以下のようになっています。

```python:list_comprehensions.py
[ (式) for (変数名) in (イテラブルオブジェクト) ]
```

イテラブルオブジェクトとは`list`や`dict`のようなイテレーションが可能なオブジェクトのことです。
変数名にはイテラブルオブジェクトの要素が1つずつ取り出され束縛されます。
式には定数や変数、`x < y`, `i * 2`といった演算の戻り値が該当します。

とても簡潔で便利なリスト内包表記ですが、実は[チューリング完全](http://metanest.jp/tm/tm.html)であることが知られています。つまり、リスト内包表記では計算機によって原理上可能な処理をすべて行うことができるということです！
このリスト内包表記がうどんの麺のように見えることから、

- コードは1行
- コードの先頭は`[`
- コードの末尾は`]`

以上3つの制約を満たすコードを<b>1本うどんコード</b>と命名し、[AtCoder]()の問題を<b>リスト内包表記をひたすらに悪用した</b>1本うどんコードで解いてみました。

### 0. [Knapsack 1](https://atcoder.jp/contests/dp/tasks/dp_d)
突き出しは競技プログラミングの代表例ナップサック問題です！

```python:knapsack.py
[print(ks([0]*(W+1), WV, N, W)) for NW in [list(map(int, input().split()))] for N, W in zip(NW[0:1], NW[1:]) for WV in [[list(map(int, input().split())) for _ in range(0, N)]] for ks in [lambda dp,WV,N,W: dp[W] if N == 0 else ks(list(reversed([dp[w-WV[N-1][0]]+WV[N-1][1] if w-WV[N-1][0] >= 0 and dp[w-WV[N-1][0]]+WV[N-1][1] > dp[w] else dp[w] for w in range(W, -1, -1)])), WV, N-1, W)]]
```
え？何が書いてあるか分からない？本当に動くのか？[もちろんちゃんと動きますよ](https://atcoder.jp/contests/dp/submissions/27133814)。
動くのは分かったけどワケワカンナイヨーという方が大半だと思います。というか記事執筆時点で筆者にも上のコードが何をやっているのかよく分からなくなってきているので、まずは簡単な例から見ていきましょう。

### 1. [Placing Marbles](https://atcoder.jp/contests/abs/tasks/abc081_a)
<b>問題文</b>
>すぬけ君は1,2,3の番号がついた3つのマスからなるマス目を持っています。 各マスには0か1が書かれており、マス$i$には$s_i$が書かれています。すぬけ君は1が書かれたマスにビー玉を置きます。ビー玉が置かれるマスがいくつあるか求めてください。


普通に書くと以下のようになります。

```python:basic.py
s = input()
print(s.count('1'))
```
pythonの`input()`は1行を文字列として読み込むので、文字の`'1'`を数えてあげればよいです。
このコードを1本うどんコードに直してみましょう！

```python:udon.py
[print(input().count('1'))]
```
そのままですね。
鋭い方は、`print()`がリストの中に入っているのはヤバくないかと感じるかもしれません。しかし、pythonの関数は必ず値を返すようになっており、デフォルトの戻り値は`None`です。`print()`の戻り値は`None`なのでリストの要素として正しく評価されます。

### 2. [Product](https://atcoder.jp/contests/abs/tasks/abc086_a)
<b>問題文</b>
>シカのAtCoDeerくんは二つの正整数$a$,$b$ を見つけました。$a$と$b$の積が偶数か奇数か判定してください。

普通に書くと以下のようになります。

```python:basic.py
a, b = map(int, input().split())

if a*b % 2 == 1:  print("Odd")
else: print("Even")
```
`map(int, input().split())`の部分で入力を空白区切りで受け取って、それぞれ整数に変換しています。
素直にあまりを見て偶奇を判定してあげればよいです。
このコードを1本うどんコードに直してみましょう！

```python:udon.py
[num := list(map(int, input().split())), print("EOvdedn"[num[0]*num[1]%2::2])]
```
なにやら怪しい構文が２つも出てきましたね。順に解説します。

#### [代入式(セイウチ演算子)](https://docs.python.org/ja/3.8/whatsnew/3.8.html#assignment-expressions)
Python3.8から追加された機能です。左辺を変数名として右辺の値を束縛し即時評価します。


```example.py
if (n := len(miroku)) > 567*(10 ** 7):
    print("this list is too long! {n} elements, expected <= 100000")
```

代入文は`n := len(miroku)`の部分で`len(miroku)`の値を`n`に束縛しています。このように代入式によって`len()`を何度も呼び出すことを回避できます。
<font color=crimson><b>本来は1本うどんコードのような用途で代入文を使用してはいけません</b></font>が、リストの中では変数定義ができないため、代入文によって変数に値を束縛しています。

#### [スライス](https://docs.python.org/ja/3.8/reference/expressions.html#slicings)
スライスはリストの一部を切り出したオブジェクトです。スライスの記法は以下のようになっています。

```slice.py
slice = List[start:stop:step]
```
Listの`start`番目のインデックスから`step`番目のインデックスまで、`step-1`個ずつ飛ばしで要素を格納したリストを得られます。
いくつか例を見てみましょう。

```example.py
a = [0, 1, 2, 4, 5, 6, 7, 8, 9]
a_1 = a[0:5:1] # a_1 = [0, 1, 2, 3, 4]
a_2 = A[0:5:2] # a_2 = [0, 2, 4]
a_3 = A[0::2]  # a_3 = [0, 2, 4, 6, 8]
```
値を省略することもでき、省略すると`start=0`, `stop=len(List)`,`step=1`となります。
Pythonでは文字列は文字のリストですから,

```string.py
print("YNeos"[0::2]) # Yes
print("YNeos"[1::2]) # No
```
というスライスが得られる訳です。<font color=crimson><b>可読性が下がるのでスライスをこのように利用してはいけません</b></font>が、リストの中で`if else`を書くよりは可読性が高いので1本うどんコードでは積極的に利用していきます。

これら2つが分かるようになると先の`udon.py`が読めるようになっていると思います。
ここからはギアを上げて`for`を使ったリスト内包表記をしていきたいと思います！

### 3. [Card Game for Two](https://atcoder.jp/contests/abs/tasks/abc088_b)
<b>問題文</b>
>$N$枚のカードがあります. $i$枚目のカードには, $a_i$という数が書かれています.
Alice と Bob は, これらのカードを使ってゲームを行います. ゲームでは, Alice と Bob が交互に 1 枚ずつカードを取っていきます. Alice が先にカードを取ります.
2 人がすべてのカードを取ったときゲームは終了し, 取ったカードの数の合計がその人の得点になります. 2 人とも自分の得点を最大化するように最適な戦略を取った時, Alice は Bob より何点多く取るか求めてください.

そのとき一番大きい数が書かれたカードを取るのが最適なので、その場合のAliceとBobの得点を求めて足せば良いです。

```python:basic.py
N = int(input())
A = list(map(int, input().split()))

A.sort(reverse=True)
Alice = sum(A[0::2])
Bob   = sum(A[1::2])
print(Alice - Bob)
```
早速スライスを活用しています。これは正しいスライスの使い方ですね。
それではこのコードを1本うどんコードに直して行きましょう！

```python:udon.py
[print(sum(A[0::2]) - sum(A[1::2])) for _ in [input()] for A in [sorted(list(map(int, input().split())), reverse=True)]]
```
一気に読みにくくなりましたね。しかし、これが今回書いた1本うどんコードの中で最も簡素なものです。
ちょっと読みやすくしてみましょう。

```python:udon.py
[
  print(sum(A[0::2]) - sum(A[1::2])) # 式は最後に
    for _ in [input()] # 最初の評価されるのはここの input()
      for A in [sorted(list(map(int, input().split())), reverse=True)] # 2番目はここのinput()
]
```
インデントして少しだけ見やすくなりました。

```python:list_comprehensions.py
[ (式) for (変数名) in (イテラブルオブジェクト) ]
```
リスト内包表記では。`イテラブルオブジェクト` > `変数名` > `式` の順で評価されます。
また、`for文`を入れ子にしたときは一番外側の`for`から評価されます。
最初の`for文`のイテラブルオブジェクトは`[input()]`ですが、これは式のみのリスト内表表記とみなすことができ、先に中の`input()`が評価されてから、リストとして評価されます。
これらのことが分かると`basic.py`と`udon.py`が全く同じことをしていると分かりますね。
今回は`for文`を使って入力を受け取りましたが、コード長が少し長くなってしまうので基本的には代入式を使って入力を受け取ります。
<font color=crimson><b>イテラブルオブジェクトをリスト内包表記で生成するのは可読性を著しく損なうので止めましょう</b></font>

### 4. [Otoshidama](https://atcoder.jp/contests/abs/tasks/abc085_c)
<b>問題文</b>
>日本でよく使われる紙幣は、10000円札、5000円札、1000円札です。以下、「お札」とはこれらのみを指します。
青橋くんが言うには、彼が祖父から受け取ったお年玉袋にはお札が$N$枚入っていて、合計で$Y$円だったそうですが、嘘かもしれません。このような状況がありうるか判定し、ありうる場合はお年玉袋の中身の候補を一つ見つけてください。なお、彼の祖父は十分裕福であり、お年玉袋は十分大きかったものとします。
<b>制約</b>
$1≤N≤2000$
$1000≤Y≤2×10^7$
$N$は整数である。
$Y$は 1000 の倍数である。

$O(N^3)$ではTLEするのでちょっと難しいですが、実は10000円札と5000円札の枚数を決めれば合計が$Y$円になるまでに1000円札が何枚必要か自然に決まるので計算量を$O(N^2)$に落とせます。
普通に書くとこのようになります。

```python:basic.py
N, Y = map(int, input().split())

a, n, s = [-1, -1, -1]
for x in range(0, N+1):
    for y in range(0, N+1-x):
        z = N - (x + y)
        if 10000*x + 5000*y + 1000*z == Y:
            a, n, s = [x, y, z]

print(a, n, s)
```
このコードを1本うどんコードに直してみましょう！今回ははじめからインデントしておきます。

```python:udon.py
[NY := list(map(int, input().split())), ans := [-1,-1,-1], [ans := [x, y, NY[0]-x-y] for x in range(0, NY[0]+1) for y in range(0, NY[0]+1-x) if 10000*x + 5000*y + 1000*(NY[0]-x-y) == NY[1]], print(ans[0], ans[1], ans[2])]
```

```udon_indent.py
[
  NY := list(map(int, input().split())), 
  ans := [-1,-1,-1], 
  [
    ans := [x, y, NY[0]-x-y] 
      for x in range(0, NY[0]+1) 
        for y in range(0, NY[0]+1-x) 
          if 10000*x + 5000*y + 1000*(NY[0]-x-y) == NY[1]
  ], 
  print(ans[0], ans[1], ans[2])
]
```
代入式では複数の変数名に値を束縛することはできないので$N$と$Y$をまとめてリストとして受け取っています。
やっていることは同じですね。少し特殊なのがリスト内表表記内での`if`の使い方です。

```python:list_comprehensions_if.py
[ (for式) for (変数名) in (イテラブルオブジェクト) if (if式)]
```
リスト内表表記内では`if`を使うことができます。ここでの`if`は制御構文としての`if文`ではなく、内包表記でのみ使える`comp_if`という構文です。`comp_if`の中の(if式)が`True`になるときだけ`for文`の中の式(for式)が評価されます。
つまり上の`udon_indent.py`では`ans := [x, y, NY[0]-x-y]`が評価されるのは`if 10000*x + 5000*y + 1000*(NY[0]-x-y) == NY[1]`が`True`になるときだけ、ということになります。
<font color=crimson><b>今更ですが、リスト内包表記をリストを作成する以外の目的で使用するのは可読性を著しく損なうので止めましょう</b></font>

### 5. [Some Sums](https://atcoder.jp/contests/language-test-202001/tasks/abc083_b?lang=ja) 

<b>問題文</b>
>$1$以上$N$以下の整数のうち、$10$進法での各桁の和が$A$以上$B$以下であるものの総和を求めてください。

実際に確かめて足せば良いです。一旦文字列にしてから、各桁を整数に戻して足します。

```python:basic.py
N, A, B = map(int, input().split())
ans = 0
for n in range(0, N+1):
    s = sum(list(map(int, str(n))))
    if A <= s <= B: 
        ans += n
print(ans)
```

このコードを1本うどんコードに直してみましょう！

```python:udon.py
[NAB:=list(map(int, input().split())), print(sum([n if NAB[1] <= sum(list(map(int, str(n)))) <= NAB[2] else 0 for n in range(0, NAB[0]+1)]))]
```

毎度のことながら見にくいのでインデントします。

```python:udon_indent.py
[
  NAB:=list(map(int, input().split())), 
  print(
    sum(
      [
        n if NAB[1] <= sum(list(map(int, str(n)))) <= NAB[2] else 0 
          for n in range(0, NAB[0]+1)
      ]
    )
  )
]
```
`for文`の中で`if`が使えることから当然`if else`も使うことができます。が、こちらも制御構文としての`if else文`ではなく、三項演算の`if else`です。`if`に3つも意味を持たせるなよ。

```python:list_comprehensions_if_else.py
[(Trueの場合の値) if (if式) else (Falseの場合の値) (for式) for (変数名) in (イテラブルオブジェクト) ]
```
`if else`を使う場合は前に来ます。式なので。他に語るべきことは何もないので、何も語りません。

### 6. [二分探索の練習問題](https://atcoder.jp/contests/typical-algorithm/tasks/typical_algorithm_a?lang=ja) 
<b>問題文</b>
>長さ $N$ の整数列 $A_0,…,A_{N−1}$ が与えられます。この数列は小さい値から順番に並ぶようにソートされています。
また、整数$K$が与えられます。$A_i ≥ K$であるようなインデックス$i$のうち、最小のものを出力してください。ただし、そのような $i$ が存在しない場合は $-1$ を出力してください。

問題文に書いてあることを素直にやります。Pythonには二分探索用のライブラリがあるのでそれを利用します。

```python:basic.py
import bisect

N, K = map(int, input().split())
A = list(map(int, input().split()))

idx = bisect.bisect_left(A, K)
if idx == len(A): 
  idx = -1

print(idx)
```

このコードを1本うどんコードに直してみましょう！既に嫌な予感がしている人がいるかもしれません。正しいです。

```python:udon.py
[K := list(map(int, input().split()))[1], A:= list(map(int, input().split())), print(-1 if (idx := [bisect.bisect_left(A, K) for bisect in [__import__("bisect")]][0]) == len(A) else idx)]
```
moduleというつけ汁によって完成する一本うどんコードはさながら[水沢うどん](https://ja.wikipedia.org/wiki/%E6%B0%B4%E6%B2%A2%E3%81%86%E3%81%A9%E3%82%93)といったところでしょうか。

```python:udon_indent.py
[
  K := list(map(int, input().split()))[1], 
  A:= list(map(int, input().split())), 
  print(
    -1 if (idx := [bisect.bisect_left(A, K) for bisect in [__import__("bisect")]][0]) == len(A) 
    else idx
  )
]
```
`module`はオブジェクトなので、当然リスト内包表記内でも使えます(えぇ……)。
ついでに言うと`__funcname__`のように`__`で挟まれたメソッドは[Magic Method](https://docs.python.org/ja/3.8/reference/datamodel.html#special-method-lookup)といって内部で使用されるメソッドです。たとえばクラスのインスタンスの作成時には`__init__`が呼ばれ`+`演算子使用時には`__add__`が呼ばれます。このように大体の操作に対応する`Magic Method`が存在します。制御構文以外の全ての構文は`Magic Method`呼び出しの糖衣構文らしいです。
`__init__`とかはオーバーロードできないと困るのでオーバーロードができるのはまあ分かるんですが、なんで外部から`Magic Method`が呼び出せるようになってるんですかね？
そういう訳で、<font color=crimson><b>Magic Methodを外部から呼び出すのは可読性を著しく損なうので止めましょう。</b></font>


余談ですが`__funcname`のように定義されるメソッドは`Private Method`と呼ばれますが、普通に外部から呼び出せますし、`CONST`のように大文字のみで定義される変数は`定数`として扱われますが、普通に変更可能です。 ~~Privateや定数を名乗るな。~~

### 7. [Knapsack 1](https://atcoder.jp/contests/dp/tasks/dp_d)
ナップザック問題、満を持しての再登場です！

<b>問題文</b>
>$N$ 個の品物があります。品物には $1,2,…,N$ と番号が振られています。各 $i$ $(1≤i≤N)$ について、品物 $i$ の重さは $w_i$で、価値は $v_i$です。
太郎君は、$N$ 個の品物のうちいくつかを選び、ナップサックに入れて持ち帰ることにしました。 ナップサックの容量は $W$ であり、持ち帰る品物の重さの総和は $W$ 以下でなければなりません。
太郎君が持ち帰る品物の価値の総和の最大値を求めてください。

<b>制約</b>
>入力はすべて整数である。
$1≤N≤100$
$1≤W≤10^5$
$1≤w_i≤W$
$1≤v_i≤10^9$

先を見据えてin-placeにDPをします。
 
```python:basic.py
N ,W = map(int, input().split())
dp = [0]*(W+1)

for _ in range(0, N):
    weight, value = map(int, input().split())
    for w in range(W, weight-1, -1):
        if dp[w-weight] + value > dp[w]:
            dp[w] = dp[w-weight] + value

print(dp[W])
```
このコードを1本うどんコードに直してみましょう！ところでこれ、読んでる人いるんですかね？

```python:udon.py
[print(ks([0]*(W+1), WV, N, W)) for NW in [list(map(int, input().split()))] for N, W in zip(NW[0:1], NW[1:]) for WV in [[list(map(int, input().split())) for _ in range(0, N)]] for ks in [lambda dp,WV,N,W: dp[W] if N == 0 else ks(list(reversed([dp[w-WV[N-1][0]]+WV[N-1][1] if w-WV[N-1][0] >= 0 and dp[w-WV[N-1][0]]+WV[N-1][1] > dp[w] else dp[w] for w in range(W, -1, -1)])), WV, N-1, W)]]
```

例によってインデントします。

```python:udon_indent.py
[
  print(ks([0]*(W+1), WV, N, W)) 
    for NW in [list(map(int, input().split()))] 
      for N, W in zip(NW[0:1], NW[1:]) 
        for WV in [[list(map(int, input().split())) for _ in range(0, N)]] 
          for ks in 
          [
            lambda dp,WV,N,W: 
              dp[W] 
              if N == 0 
              else ks
                   (
                     list(reversed(
                       [
                         dp[w-WV[N-1][0]]+WV[N-1][1] 
                         if w-WV[N-1][0] >= 0 and dp[w-WV[N-1][0]]+WV[N-1][1] > dp[w] 
                         else dp[w] 
                           for w in range(W, -1, -1)
                       ]))
                     , WV, N-1, W
                   )
          ]
]
```
コードが長すぎてもはやどこでインデントしたらいいか分かりません。~~たすけて〜〜〜~~
このコードの圧倒的なコシ(理解不能さ)はさながら[讃岐うどん](https://ja.wikipedia.org/wiki/%E8%AE%83%E5%B2%90%E3%81%86%E3%81%A9%E3%82%93)といったところでしょうか。
こんなコード書いてくるやつがいたらこっちの精神が[伊勢うどん](https://ja.wikipedia.org/wiki/%E4%BC%8A%E5%8B%A2%E3%81%86%E3%81%A9%E3%82%93)にようにブチブチに切れてしまいそうです。

[lambda](https://docs.python.org/ja/3.8/reference/expressions.html?highlight=lambda#lambda)関数はオブジェクトなのでリスト内包表記で使用することができます。~~できちゃだめだろ~~
しかもlambdaに名前をつけることができるのでlambda再帰ができます。~~できちゃだめだろ~~
セグメンテーションフォルトは[ifの短絡評価](https://docs.python.org/ja/3.8/library/stdtypes.html#boolean-operations-and-or-not)によって回避しています。
<font color=crimson><b>リスト内包表記でlambda関数を回すなんてやってはいけませんし、lambda再帰なんて言語道断です。可読性を著しく損なうので止めましょう。</b></font>

### 8. [Union Find](https://atcoder.jp/contests/atc001/tasks/unionfind_a)
ラスボス、Union Findです。Union Findとは素集合を管理するデータ構造です。

<b>問題文</b>
>この問題は、講座用問題です。ページ下部に解説が掲載されています。$N$ 頂点の、単純とは限らない無向グラフを考えます。 初期状態では、頂点のみが存在し、辺は全く存在せず、全ての頂点が孤立しているとします。以下の $2$ 種類のクエリが、$Q$ 回与えられます。
・ 連結クエリ： 頂点 $A$ と、頂点 $B$ を繋ぐ辺を追加します。
・ 判定クエリ： 頂点 $A$ と、頂点 $B$ が、連結であるかどうか判定します。連結であれば Yes、そうでなければ No を出力します。
クエリを順番に処理し、判定クエリへの回答を出力して下さい。 この際、同じ辺が何度も追加されることや、自分自身への辺が追加されることもある事に注意してください。
連結であるとは、頂点 $A$ から頂点 $B$ まで辺をたどって到達可能であることを意味します。 $A$ と $B$ が同じ頂点の場合、連結であると定義します。 グラフは無向であるため、連結クエリによって頂点 $A$,$B$ 間の辺が追加されると、$A$ から $B$ へも $B$ から $A$ へも辿れるようになります。

```python:basic.py
class UnionFind:
    def __init__(self, N):
        self.par = [i for i in range(0, N)]
    
    def find(self, x):
        if x != self.par[x]: 
            self.par[x] = self.find(self.par[x])
        return self.par[x]

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        self.par[y] = x
    
    def same(self, x, y):
        return self.find(self.par[x]) == self.find(self.par[y])

N, Q = map(int, input().split())

uf = UnionFind(N)
for _ in range(0, Q):
    P, A, B = map(int, input().split())
    if P == 0:
        uf.unite(A, B)
    else:
        print("YNeos"[not uf.same(A, B)::2])
```

このコードを1本うどんコードに直してみましょう！

```python:udon.py
[NQ:=list(map(int,input().split())),[uf.unite(PAB[1],PAB[2]) if PAB[0]==0 else uf.same(PAB[1],PAB[2]) for uf in [type("UnionFind",(),{"__init__":(lambda self,N:setattr(self,"par", [i for i in range(0, N)])),"find":(lambda self,x: self.par[x] if x!=self.par[x] and self.par.__setitem__(x,self.find(self.par[x])) else self.par[x]),"unite":(lambda self,x,y: self.par.__setitem__(self.find(y),self.find(x))),"same":(lambda self,x,y:print("YNeos"[self.par[self.find(x)]!=self.par[self.find(y)]::2]))})(NQ[0])] for _ in range(0, NQ[1]) for PAB in [list(map(int, input().split()))]]]
```

```python:udon_indent.py
[
  NQ:=list(map(int,input().split())),
  [
    uf.unite(PAB[1],PAB[2]) if PAB[0]==0 else uf.same(PAB[1],PAB[2]) 
      for uf in 
      [
        type("UnionFind",(),
          {
            "__init__":(lambda self,N:setattr(self,"par", [i for i in range(0, N)])),
            "find":(lambda self,x: self.par[x] if x!=self.par[x] and self.par.__setitem__(x,self.find(self.par[x])) else self.par[x]),
            "unite":(lambda self,x,y: self.par.__setitem__(self.find(y),self.find(x))),
            "same":(lambda self,x,y:print("YNeos"[self.par[self.find(x)]!=self.par[self.find(y)]::2]))
          })(NQ[0])
      ] 
        for _ in range(0, NQ[1]) 
          for PAB in [list(map(int, input().split()))]
  ]
]
```
[type関数](https://docs.python.org/ja/3/library/functions.html#type)ではオブジェクトの型をチェックすることができます。が、type関数で新しい型を定義することもできます。関数に異なる２つの機能を持たせちゃダメだろ。type関数で新しい型を定義する場合はjson形式で関数名と関数のペアを指定します。関数はlambda関数でも良いので、よしなに定義します。
find関数では再帰で代入もしないといけないのでifの短絡評価とMagic Methodでむりやり実現しています。

<font color=#E60012><b>本来は1本うどんコードのような用途で代入文を使用してはいけません。</b></font>
<font color=#F39800><b>イテラブルオブジェクトをリスト内包表記で生成するのは可読性を著しく損なうので止めましょう。</b></font>
<font color=#FFF100><b>今更ですが、リスト内包表記をリストを作成する以外の目的で使用するのは可読性を著しく損なうので止めましょう。</b></font>
<font color=#009944><b>Magic Methodを外部から呼び出すのは可読性を著しく損なうので止めましょう。</b></font>
<font color=#0068B7><b>リスト内包表記でlambda関数を回すなんてやってはいけませんし、lambda再帰なんて言語道断です。可読性を著しく損なうので止めましょう。</b></font>
<font color=#1D2088><b>ifの短絡評価を用いてif文を表現するのは止めましょう。</b></font>
<font color=#920783><b>type関数を新しい型を定義するために使ってはいけません。</b></font>


### 9. まとめ
いかがでしたか？ここまで耐え抜いて頂いて感謝しています。僕はもうダメです。<b>1本うどんコードなんて二度と書きません</b>。

#### 追記
GitHubにコードを上げたので見たい方はこちらを見てください。
[ugis70194/Python3_UDON_codes](https://github.com/ugis70194/Python3_UDON_codes)

### 参考資料
- [Pythonリスト内包表記の使い方](https://note.nkmk.me/python-list-comprehension/)
- [用語集 — Python 3.8.10 ドキュメント function](https://docs.python.org/ja/3.8/glossary.html#term-function)
- [用語集 — Python 3.8.10 ドキュメント return文](https://docs.python.org/ja/3.8/reference/simple_stmts.html#return) 
- [【Python】競技プログラミング 基本入力まとめ](https://qiita.com/ell/items/1f519aff0cdc3cf16284)
- [Pythonのinput関数でキーボードからの入力を取得](https://note.nkmk.me/python-input-usage/)
- [Pythonのmap()でリストの要素に関数・処理を適用](https://note.nkmk.me/python-map-usage/)
- [pythonのアンダーバーこれなんやねん](https://qiita.com/kiii142/items/6879cb065ad4c5f0b901)
- [3. データモデル — Python 3.8.10 ドキュメント](https://docs.python.org/ja/3.8/reference/datamodel.html#special-method-lookup)
- [Pythonの特殊メソッド一覧を備忘録としてまとめてみた。](https://qiita.com/y518gaku/items/07961c61f5efef13cccc)
- [糖衣構文](https://ja.wikipedia.org/wiki/%E7%B3%96%E8%A1%A3%E6%A7%8B%E6%96%87)