1
2

More than 1 year has passed since last update.

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

Posted at

前回のつづきから
項目をうまくまとめようとしても、あんましうまくまとまらんかった(言い訳)

文法

  • Java

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

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

変数

Java
String msg = "Hello world";
var msg2 = "Hello world";
Python
msg = "Hello world"

Pythonは接頭語の必要なし。

アンパック

タプル、リストの値を変数に一変に代入できる。便利らしい。

Python
x = (1, 2, 3, 4, 5)
a, b, c, d, e = x

*を頭につけた変数には割り当てられていない値が全部そこに入る。

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

定数

Java
final var MSG = "Hello world";
Python
MSG = "Hello world"
MSG = "Hello"

Pythonにはfinalconstもないので、大文字のスネークケースという命名規則に基づくものを定数とみなしていきましょうということらしい。
つまり口約束。
constぐらいはあってもよさそう。
って思って調べて見らたらFinalがありました。

Python
from typing import Final

MSG: Final[str] = "Hello world"

演算子

論理演算子

Java Python
&& and
|| or
! not

Pythonはより英文っぽく読める!
個人的に否定がnotなのはめっちゃいいと思う。!は1文字だし細いし見逃しやすい気がする。
注意点としてはand, orが必ずしも真偽値を返さないこと。

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
n = 10
print(2 <= n <= 12)
True

三項演算子

Java
var n = 10;
var x = n == 10 ? "OK" : "NG";
Python
n = 10
x = "OK" if n == 10 else "NG"

Pythonのほうが文章っぽくて魔術感が薄い印象。

if文

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
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
    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
x = 0
match x:
    case 1:
        print("case1")
    case 2:
        print("case2")
    case _:
        print("default")

match文は3.10から登場した新しい構文らしい。
パターンマッチングなので、タプルとかクラスの構造で細かくケースを作ることができ、より柔軟ということになる。
単に値のマッチングだけできる構文なんていらないですからね。enumがあればよし。

for文

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
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
    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
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

breakcontinueについては同様。
Pythonはなんとforに対してもelseを書ける。
Javaでやろうとしたらフラグを用意しないと実現できないですね(ですよね?)

while文

Java
    public static void main(String[] args) {
        var n = 0;
        while (n < 2) {
            System.out.println(n);
            n++;
        }
    }
Python
n = 0
while n < 2:
    print(n)
    n += 1

違いほぼなし。

リスト内包表記

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
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
    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
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')

catchexceptthrowraiseの違いがある。
またPythonではelseが書けることによって、予想していなかった例外は意図的にキャッチしないようにできる。
try elseでしっかりコードを整理しようということか。

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

pass文

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

while True:
    pass
    print("PASS")

なにもしないことを明記できる。
ループでのcontinueとの違いは、passのあとに処理が実行されるところ。

with文

Python
with open("sample.txt", "r") as f:
    print f.read()

try finallyを毎回書くのが億劫のために用意された文らしい。
https://peps.python.org/pep-0343/
contextmanagerなるものが前処理、後処理を担当している。
この辺の深掘りは追々勉強していこうと思います。

del文

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
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
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
def createFibList(n=0):

リスト, ディクショナリのデフォルト値は要注意。デフォルト値で空のリスト, ディクショナリを生成すると、そこで生成した1つのインスタンスを参照する=シングルトンになるので、スレッドセーフにならず思わぬ挙動になりがち。

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
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
  public static void main(String[] args) {
    Function<Integer, Integer> f = x -> x + 1;
    System.out.println(f.apply(1));
  }
Python
f = lambda x: x + 1
print(f(1))

lambda 引数: 返り値で記載ができる。
lambdaって書くのがJavaより冗長な感じがする。
っつってもJavaのlambda式は明示的に型を記載してあげる必要があるから、文章量的にはJavaのほうが多いか。

import

Java
import java.math.BigDecimal;
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
 /**
   * Javadoc
   *
   * @param args
   */
  public static void main(String[] args) {
    // コメント!
  }
Python
def main(args)
    """docstring"""
    # コメント!

ドキュメンテーション文字列はクラスとかメソッドのヘッダの上に書くか下に書くかの違いがある。

クラス定義

Java
class MyClass {
}
Python
class MyClass:
    pass

記法の違いは特になし。

Java
class MyClass {

  static int i = 12345;

  String name;

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

x = new MyClass("test");
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
class DeriverdClassName extends BaseClassName {
}
Python
class DeriverdClassName(BaseClassName):
    pass

記法の違いはextends()か。
extendsのほうが文章っぽい感じするからそっちが好み。

オブジェクト指向

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

型アノテーション

Python
def f(name: str) -> str:
        return "hello world", name

書き方はTypeScriptとかScalaみたいな感じ。
Pythonでも大規模開発が行われることが多くなり、その結果型が書けたほうがいいよね的な感じで追加されたのでしょう。
強制力はなくコメントみたいなもの。
でも、チェックツールを使うことでエディタで静的なチェックもできる。
なにより型の定義が書かれていたほうが読みやすい。

この辺で終わりにするか

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

1
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2