前回のつづきから
項目をうまくまとめようとしても、あんましうまくまとまらんかった(言い訳)
文法
-
Java
- 文末は
;
で表現 - ブロックは
{}
で表現- if, forなどで省略可能な書き方もあるけど、
{}
で囲ったほうがいいと言われている(1行分しか実行されないため思わぬバグを生む可能性あり)
- if, forなどで省略可能な書き方もあるけど、
- 文末は
-
Python
- 文末は改行で表現
-
;
も許可されているが非推奨
-
- ブロックはインデントで表現
- ヘッダの部分(if, forなどの始まりの部分、クラス,関数定義)は
:
で区切る
- ヘッダの部分(if, forなどの始まりの部分、クラス,関数定義)は
- 文末は改行で表現
変数
String msg = "Hello world";
var msg2 = "Hello world";
msg = "Hello world"
Pythonは接頭語の必要なし。
アンパック
タプル、リストの値を変数に一変に代入できる。便利らしい。
x = (1, 2, 3, 4, 5)
a, b, c, d, e = x
*
を頭につけた変数には割り当てられていない値が全部そこに入る。
タプルは性質上、中身の数が不変になることが多そうだから、アンパックの記述が使いやすそうだけど、中身の数が場合によって異なることが多そうなリストだと実践的には使いにくいのかなあ。
定数
final var MSG = "Hello world";
MSG = "Hello world"
MSG = "Hello"
Pythonにはfinal
もconst
もないので、大文字のスネークケースという命名規則に基づくものを定数とみなしていきましょうということらしい。
つまり口約束。
const
ぐらいはあってもよさそう。
って思って調べて見らたらFinalがありました。
from typing import Final
MSG: Final[str] = "Hello world"
演算子
論理演算子
Java | Python |
---|---|
&& | and |
|| | or |
! | not |
Pythonはより英文っぽく読める!
個人的に否定がnot
なのはめっちゃいいと思う。!
は1文字だし細いし見逃しやすい気がする。
注意点としてはand
, or
が必ずしも真偽値を返さないこと。
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
のほうが好まれているのかなぁ。
またチェーンすることも可能。こちらも読みやすい。
n = 10
print(2 <= n <= 12)
True
三項演算子
var n = 10;
var x = n == 10 ? "OK" : "NG";
n = 10
x = "OK" if n == 10 else "NG"
Pythonのほうが文章っぽくて魔術感が薄い印象。
if文
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("もっと");
}
}
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文
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;
}
}
x = 0
match x:
case 1:
print("case1")
case 2:
print("case2")
case _:
print("default")
match文は3.10から登場した新しい構文らしい。
パターンマッチングなので、タプルとかクラスの構造で細かくケースを作ることができ、より柔軟ということになる。
単に値のマッチングだけできる構文なんていらないですからね。enumがあればよし。
for文
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());
}
}
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))
を使用すること。
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);
}
}
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文
public static void main(String[] args) {
var n = 0;
while (n < 2) {
System.out.println(n);
n++;
}
}
n = 0
while n < 2:
print(n)
n += 1
違いほぼなし。
リスト内包表記
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()));
}
vec = [-4, -2, 0, 2, 4]
print([x * 2 for x in vec])
print([x for x in vec if 0 <= x])
比較対象はStreamAPIであっているはず。
for文はいくつでも入れることができるけど、複数書いてあると絶対読むのがムズい。
目が慣れるのに時間がかかりそうです。
例外処理
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");
}
}
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文
a = 4
if a % 2 == 0:
print("Even")
else:
pass
while True:
pass
print("PASS")
なにもしないことを明記できる。
ループでのcontinue
との違いは、passのあとに処理が実行されるところ。
with文
with open("sample.txt", "r") as f:
print f.read()
try finallyを毎回書くのが億劫のために用意された文らしい。
https://peps.python.org/pep-0343/
contextmanager
なるものが前処理、後処理を担当している。
この辺の深掘りは追々勉強していこうと思います。
del文
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()
みたく関数じゃないんだろ、今度ちゃんと調べよう。
関数定義
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));
}
}
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
で同じだった。
デフォルト値
引数にはデフォルト値を設定できる。
def createFibList(n=0):
リスト, ディクショナリのデフォルト値は要注意。デフォルト値で空のリスト, ディクショナリを生成すると、そこで生成した1つのインスタンスを参照する=シングルトンになるので、スレッドセーフにならず思わぬ挙動になりがち。
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
[1]
[1, 2]
[1, 2, 3]
キーワード引数
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式
public static void main(String[] args) {
Function<Integer, Integer> f = x -> x + 1;
System.out.println(f.apply(1));
}
f = lambda x: x + 1
print(f(1))
lambda 引数: 返り値
で記載ができる。
lambdaって書くのがJavaより冗長な感じがする。
っつってもJavaのlambda式は明示的に型を記載してあげる必要があるから、文章量的にはJavaのほうが多いか。
import
import java.math.BigDecimal;
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
コメント
/**
* Javadoc
*
* @param args
*/
public static void main(String[] args) {
// コメント!
}
def main(args)
"""docstring"""
# コメント!
ドキュメンテーション文字列はクラスとかメソッドのヘッダの上に書くか下に書くかの違いがある。
クラス定義
class MyClass {
}
class MyClass:
pass
記法の違いは特になし。
class MyClass {
static int i = 12345;
String name;
MyClass(String name) {
this.name = name;
}
}
x = new MyClass("test");
class MyClass:
i = 12345
def __init__(self, name):
self.name = name
x = MyClass("test")
Pythonだとインスタンス変数は特殊メソッド__init__()
内で定義する。
__init__()
がコンストラクタ、っていうよりはFactoryメソッドって感じか。
インスタンス化もPythonのほうは関数を呼んでいるように読める。
また__init__()
に限らず、Pythonのクラス内で定義するメソッドは慣習的にself
とするらしい。
これがJavaでいうthis
の代わりかと認識。
この辺は慣れが必要そう。
継承
class DeriverdClassName extends BaseClassName {
}
class DeriverdClassName(BaseClassName):
pass
記法の違いはextends
か()
か。
extendsのほうが文章っぽい感じするからそっちが好み。
オブジェクト指向
また継承に関してはJavaといろいろ差異がある。
多重継承ができる点やinterfaceがない点、オーバーロードができない点とか。
これらについては、オブジェクト指向の違いとして別で書くかもしれなくもなくもない。
他にもtype
というものやメタクラスなど、大筋としてオブジェクト指向に違いはないけどいろいろ違うところがあるということで、そこのところをお勉強中。
型アノテーション
def f(name: str) -> str:
return "hello world", name
書き方はTypeScriptとかScalaみたいな感じ。
Pythonでも大規模開発が行われることが多くなり、その結果型が書けたほうがいいよね的な感じで追加されたのでしょう。
強制力はなくコメントみたいなもの。
でも、チェックツールを使うことでエディタで静的なチェックもできる。
なにより型の定義が書かれていたほうが読みやすい。
この辺で終わりにするか
アノテーションとデコレーターとか、ジェネレーターとかyield式とか、他にも拾いきれてない内容はたくさんあるかとは思いますが、大体は書けてるかなぁ...
今後追記しまーす。