Java頭からPython頭に切り替える(基礎編2)

[前回のつづき](https://qiita.com/kei3524848/items/53d84c375716b17aae3a)から
項目をうまくまとめようとしても、あんましうまくまとまらんかった（言い訳）

## 文法

* Java
    * 文末は`;`で表現
    * ブロックは`{}`で表現
        * if, forなどで省略可能な書き方もあるけど、`{}`で囲ったほうがいいと言われている(1行分しか実行されないため思わぬバグを生む可能性あり)

* Python
    * 文末は改行で表現
        * `;`も許可されているが非推奨
    * ブロックはインデントで表現
        * ヘッダの部分(if, forなどの始まりの部分、クラス,関数定義)は`:`で区切る

## 変数
```Java:Java
String msg = "Hello world";
var msg2 = "Hello world";
```
```Python:Python
msg = "Hello world"
```
Pythonは接頭語の必要なし。

### アンパック
タプル、リストの値を変数に一変に代入できる。便利らしい。
```Python:Python
x = (1, 2, 3, 4, 5)
a, b, c, d, e = x
```
`*`を頭につけた変数には割り当てられていない値が全部そこに入る。

タプルは性質上、中身の数が不変になることが多そうだから、アンパックの記述が使いやすそうだけど、中身の数が場合によって異なることが多そうなリストだと実践的には使いにくいのかなあ。

### 定数
```Java:Java
final var MSG = "Hello world";
```
```Python:Python
MSG = "Hello world"
MSG = "Hello"
```
Pythonには`final`も`const`もないので、大文字のスネークケースという命名規則に基づくものを定数とみなしていきましょうということらしい。
つまり口約束。
`const`ぐらいはあってもよさそう。
って思って調べて見らたら[Final](https://docs.python.org/ja/3/library/typing.html#typing.Final)がありました。

```Python:Python
from typing import Final

MSG: Final[str] = "Hello world"
```

## 演算子
### 論理演算子
|  Java  |  Python  |
| ---- | ---- |
|  &&  |  and  |
|  \|\|  |  or |
|  !  |  not |

Pythonはより英文っぽく読める！
個人的に否定が`not`なのはめっちゃいいと思う。`!`は1文字だし細いし見逃しやすい気がする。
注意点としては`and`, `or`が必ずしも真偽値を返さないこと。
```Python:Python
string1, string2, string3 = "", "2", "3"
non_null = string1 or string2 or string3
print(non_null)
```
```
2
```
左から順に評価され、結論が決まり次第評価は終了する。
Javascriptと同様に空文字はfalseになるので、string2がtrueとなった時点で評価は終了し、その値が返却されている。

### 比較演算子
`==`, `!=`, `<=` ,`>=` ,`<`, `>`は同じ。
Pythonは加えて`is`, `is not`, `in`, `not in`がある。
言語思想的には`==`, `!=`よりも`is`, `is not`のほうが好まれているのかなぁ。

またチェーンすることも可能。こちらも読みやすい。
```Python:Python
n = 10
print(2 <= n <= 12)
```
```
True
```

### 三項演算子
```Java:Java
var n = 10;
var x = n == 10 ? "OK" : "NG";
```
```Python:Python
n = 10
x = "OK" if n == 10 else "NG"
```
Pythonのほうが文章っぽくて魔術感が薄い印象。

## if文
```Java:Java
    public static void main(String[] args) {
        var x = 0;
        if (x < 0) {
            x = 0;
            System.out.println("負数はゼロとする");
        } else if (x == 0) {
            System.out.println("ゼロ");
        } else if (x == 1) {
            System.out.println("ひとつ");
        } else {
            System.out.println("もっと");
        }
    }
```
```Python:Python
x = 0
if x < 0:
    x = 0
    print("負数はゼロとする")
elif x == 0:
    print("ゼロ")
elif x == 1:
    print("ひとつ")
else:
    print("もっと")
```
Pythonでは条件式に`()`が不要。書くこともできる。
また`else if`を省略して`elif`と書くというところに驚いた。`elif`で4文字だから空目で`else`に見えて、`else`だけなのに条件式が続くの？ってなった。
こうして並べてみると、Pythonのほうがすっきりしてるな～って感じ。

また、論理演算子のところで書いたように`and`, `or`が真偽値を返さない場合があるが、ifの条件の中だとPython側が勝手に真偽値としいて判断してくれるとのこと(`bool(x and y)`ってこと)

### switch文
```Java:Java
    public static void main(String[] args) {
        var x = 0;
        switch (x) {
            case 1:
                System.out.println("case1");
                break;
            case 2:
                System.out.println("case2");
                break;
            default:
                System.out.println("default");
                break;
        }
    }

```
```Python:Python
x = 0
match x:
    case 1:
        print("case1")
    case 2:
        print("case2")
    case _:
        print("default")
```
match文は3.10から登場した新しい構文らしい。
パターンマッチングなので、タプルとかクラスの構造で細かくケースを作ることができ、より柔軟ということになる。
単に値のマッチングだけできる構文なんていらないですからね。enumがあればよし。

## for文
```Java:Java
    public static void main(String[] args) {
        for (var i = 0; i < 5; i++) {
            System.out.println(i);
        }

        for (var i = 5; i < 10; i++) {
            System.out.println(i);
        }

        for (var i = 0; i < 10; i = i + 3) {
            System.out.println(i);
        }

        var words = new String[]{"cat", "window", "defenestrate"};
        for (var w : words) {
            System.out.println(w + " " + w.length());
        }

        var knights = new HashMap<String, String>();
        knights.put("gallahad", "the pure");
        knights.put("robin", "the braze");
        for (var e : knights.entrySet()) {
            System.out.println(e.getKey() + " " + e.getValue());
        }
    }

```
```Python:Python
for i in range(5):
    print(i)

for i in range(5, 10):
    print(i)

for i in range(0, 10, 3):
    print(i)

words = ["cat", "window", "defenestrate"]
for w in words:
    print(w, len(w))

knigths = {"gallahad": "the pure", "robin": "the braze"}
for k, v in knigths.items():
    print(k, v)
```
```
0
1
2
3
4

5
6
7
8
9

0
3
6
9

cat 3
window 6
defenestrate 12
```
数を数えるループはPythonが楽ですね。
`range()`は`Intstream.range()`と同様に指定した終了値は含まない扱いとなる。
コレクションのループの書き方にはそんなに差異はないイメージ。

ついでにインクリメントとデクリメントについて。
Pythonは`++`,`--`によるインクリメント、デクリメントをサポートしていない。
`++`は1つ増加、というのは明示的ではないということらしい。
https://peps.python.org/pep-0020/#the-zen-of-python
デクリメントしたい場合は`reversed(range(n))`を使用すること。

```Java:Java
    public static void main(String[] args) {
        for (var n = 2; n < 10; n++) {
            var isPrimeNum = true;
            for (var x = 2; x < n; x++) {
                if (n % x == 0) {
                    System.out.println(n + " " + "equals" + " " + x + " * " + (n / x));
                    isPrimeNum =  false;
                    break;
                }
            }

            if (isPrimeNum) {
                System.out.println(n + " is a prime number");
            }
        }

        for (var num = 2; num < 10; num ++) {
            if (num % 2 == 0) {
                System.out.println("Found an even number " + num);
                continue;
            }
            System.out.println("Found a number " + num);
        }
    }
```
```Python:Python
for n in range(2, 10):
    for x in range(2, n):
        if n % x == 0:
            print(n, 'equals', x, '*', n // x)
            break
    else:
        print(n, "is a prime number")

for num in range(2, 10):
    if num % 2 == 0:
        print("Found an even number", num)
        continue
    print("Found a number", num)
```
```
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3

Found an even number 2
Found a number 3
Found an even number 4
Found a number 5
Found an even number 6
Found a number 7
Found an even number 8
Found a number 9
```
`break`と`continue`については同様。
Pythonはなんとforに対しても`else`を書ける。
Javaでやろうとしたらフラグを用意しないと実現できないですね(ですよね？)

### while文
```Java:Java
    public static void main(String[] args) {
        var n = 0;
        while (n < 2) {
            System.out.println(n);
            n++;
        }
    }
```
```Python:Python
n = 0
while n < 2:
    print(n)
    n += 1
```
違いほぼなし。

### リスト内包表記
```Java:Java
  public static void main(String[] args) {
    var vec = Arrays.asList(-4, -2, 0, 2, 4);
    System.out.println(vec.stream().map(x -> x * 2).collect(Collectors.toList()));
    System.out.println(vec.stream().filter(x -> 0 <= x).collect(Collectors.toList()));
  }
```
```Python:Python
vec = [-4, -2, 0, 2, 4]
print([x * 2 for x in vec])
print([x for x in vec if 0 <= x])
```
比較対象はStreamAPIであっているはず。
for文はいくつでも入れることができるけど、複数書いてあると絶対読むのがムズい。
目が慣れるのに時間がかかりそうです。

## 例外処理
```Java:Java
    public static void main(String[] args) {
        var str = "ABC";
        try {
            var c = str.charAt(5);
            var is = new FileInputStream("");
        } catch (IOException ioe) {
            System.out.println("IOException");
        } catch (StringIndexOutOfBoundsException be) {
            System.out.println("IndexError");
            System.out.println(be);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        } finally {
            System.out.println("Finally");
        }
    }
```
```Python:Python
str = 'ABC'
try:
    c = str[5]
except IOError:
    print('IOError')
except IndexError as e:
    print('IndexError')
    print(e)
except:
    raise SystemError("'Unknown'")
else:
    print('Other')
finally:
    print('Finally')
```
`catch`と`except`、`throw`と`raise`の違いがある。
またPythonでは`else`が書けることによって、予想していなかった例外は意図的にキャッチしないようにできる。
try elseでしっかりコードを整理しようということか。

例外そのものの違いはまた別で記載。

## pass文
```python:Python
a = 4
if a % 2 == 0:
    print("Even")
else:
    pass

while True:
    pass
    print("PASS")
```
なにもしないことを明記できる。
ループでの`continue`との違いは、passのあとに処理が実行されるところ。

## with文
```python:Python
with open("sample.txt", "r") as f:
    print f.read()
```
try finallyを毎回書くのが億劫のために用意された文らしい。
https://peps.python.org/pep-0343/
`contextmanager`なるものが前処理、後処理を担当している。
この辺の深掘りは追々勉強していこうと思います。

## del文
```python:Python
a = [-1, 1, 66.25, 333, 333, 1234.5]
del a[0]
print(a)
del a[2:4]
print(a)
del a[:]
print(a)
```
```
[1, 66.25, 333, 333, 1234.5]
[1, 66.25, 1234.5]
[]
```
要素やインスタンスの削除ができる。
文であり関数ではない。
なんで`print()`みたく関数じゃないんだろ、今度ちゃんと調べよう。

## 関数定義
```Java:Java
class A {

  public static List<Integer> createFibList(int n) {
    int a = 0, b = 1;
    var result = new ArrayList<Integer>();
    while (a < n) {
      result.add(a);
      a = b;
      b = a + b;
    }
    return result;
  }

  public static void main(String[] args) {
    System.out.println(createFibList(100));
    Function<Integer, List<Integer>> f = A::createFibList;
    System.out.println(f.apply(200));
  }
}
```
```Python:Python
def createFibList(n):
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a + b
    return result


print(createFibList(100))
f = createFibList
print(f(200))
```
`（アクセス修飾子）+ 返却型 + 関数名 + 引数`と`def + 関数名 + 引数`の違い。
値を返却する場合も`return`で同じだった。

### デフォルト値
引数にはデフォルト値を設定できる。
```Python:Python
def createFibList(n=0):
```
リスト, ディクショナリのデフォルト値は要注意。デフォルト値で空のリスト, ディクショナリを生成すると、そこで生成した1つのインスタンスを参照する＝シングルトンになるので、スレッドセーフにならず思わぬ挙動になりがち。
```Python:Python
def f(a, L=[]):
    L.append(a)
    return L


print(f(1))
print(f(2))
print(f(3))
```
```
[1]
[1, 2]
[1, 2, 3]
```
### キーワード引数
```Python:Python
def parrot(voltage, state="a stiff", action="voom", type="Norweign Blue"):
    print("-- This parrot wouldn't", action, end=" ")
    print("if you put", voltage, "volts through it.")
    print("-- Lovely plumgae, the", type)
    print("-- It's", state, "!")


parrot(1000)
parrot(voltage=1000)
parrot(voltage=100000, action="VOOOOOM")
parrot(action="VOOOOM", voltage=1000000)
parrot("a million", "benefit of life", "jump")
parrot("a thousand", state="pushing up the daisies")
```
引数のデフォルト値があるからだろうけど、どの引数を渡すのかも指定ができる。
使う側がいろいろと指定できるのは便利そうだけど、一方で使うときにどう使うかを考えなきゃならなくなるのはちょっと面倒かも？

#### lambda式
```Java:Java
  public static void main(String[] args) {
    Function<Integer, Integer> f = x -> x + 1;
    System.out.println(f.apply(1));
  }
```
```Python:Python
f = lambda x: x + 1
print(f(1))
```
`lambda 引数: 返り値`で記載ができる。
lambdaって書くのがJavaより冗長な感じがする。
っつってもJavaのlambda式は明示的に型を記載してあげる必要があるから、文章量的にはJavaのほうが多いか。

### import
```Java:Java
import java.math.BigDecimal;
```
```Python:Python
from decimal import Decimal
```
PythonはJavaのように数珠繋ぎにはしない。

## アクセス修飾子
Javaには`public`, `protected`, `privatge`, `デフォルト`のアクセス修飾子があるが、Pythonにはない。
そのためPythonではお約束として、メソッド名やメンバの名前の頭に`_`, `__`が使われる。
`_`が`protected`で`__`が`private`のイメージで認識している。 

### スコープ
Javaはクラス、インスタンス、ローカルの3つ。
Pythonのスコープのルールは`LGBE`というものがある。
* L: Local
* E: Enclosing function local 
* G: Global
* B: Built-in

## コメント
```Java:Java
 /**
   * Javadoc
   *
   * @param args
   */
  public static void main(String[] args) {
    // コメント！
  }
```
```Python:Python
def main(args)
    """docstring"""
    # コメント！
```
ドキュメンテーション文字列はクラスとかメソッドのヘッダの上に書くか下に書くかの違いがある。

## クラス定義
```Java:Java
class MyClass {
}
```
```Python:Python
class MyClass:
    pass
```
記法の違いは特になし。

```Java:Java
class MyClass {

  static int i = 12345;

  String name;

  MyClass(String name) {
    this.name = name;
  }
}

x = new MyClass("test");
```
```Python:Python
class MyClass:

    i = 12345

    def __init__(self, name):
        self.name = name

x = MyClass("test")
```
Pythonだとインスタンス変数は特殊メソッド`__init__()`内で定義する。
`__init__()`がコンストラクタ、っていうよりはFactoryメソッドって感じか。
インスタンス化もPythonのほうは関数を呼んでいるように読める。

また`__init__()`に限らず、Pythonのクラス内で定義するメソッドは慣習的に`self`とするらしい。
これがJavaでいう`this`の代わりかと認識。
この辺は慣れが必要そう。

### 継承
```Java:Java
class DeriverdClassName extends BaseClassName {
}
```
```Python:Python
class DeriverdClassName(BaseClassName):
    pass
```
記法の違いは`extends`か`()`か。
extendsのほうが文章っぽい感じするからそっちが好み。

#### オブジェクト指向
また継承に関してはJavaといろいろ差異がある。
多重継承ができる点やinterfaceがない点、オーバーロードができない点とか。
これらについては、オブジェクト指向の違いとして別で書くかもしれなくもなくもない。
他にも`type`というものやメタクラスなど、大筋としてオブジェクト指向に違いはないけどいろいろ違うところがあるということで、そこのところをお勉強中。

## 型アノテーション
```Python:Python
def f(name: str) -> str:
        return "hello world", name
```
書き方はTypeScriptとかScalaみたいな感じ。
Pythonでも大規模開発が行われることが多くなり、その結果型が書けたほうがいいよね的な感じで追加されたのでしょう。
強制力はなくコメントみたいなもの。
でも、チェックツールを使うことでエディタで静的なチェックもできる。
なにより型の定義が書かれていたほうが読みやすい。

# この辺で終わりにするか
アノテーションとデコレーターとか、ジェネレーターとかyield式とか、他にも拾いきれてない内容はたくさんあるかとは思いますが、大体は書けてるかなぁ...
今後追記しまーす。