【Linux】rsync
Linuxのコマンドrsyncについてまとめいきたいと思います。
rsyncとは
リモート、ローカルにかかわらずファイル、ディレクトリのコピーを行うコマンドです。 バックアップを作成したり、リモートディレクトリの同期によく利用されます。
書式
rsync [オプション] コピー元 コピー先
インストール
rsync がインストールされていない場合は yum を使って入れる。
# yum install rsync
オプション
オプション | 説明 |
---|---|
-a | コピー元のディレクトリを再帰的に所有者・グループ・パーミッション・タイムスタンプをそのままコピーします。オプション「-rlptgoD」と同じです。 |
-r | ディレクトリ内を再帰的にコピーします。このオプションを指定しないとディレクトリ内が全くコピーされません。 |
-l | シンボリックリンクをそのままコピーします。 |
-p | パーミッションをそのままコピーします。 |
-t | タイムスタンプをそのままコピーします。 |
-g | グループをそのままコピーします。 |
-o | 所有者をそのままコピーします。 |
-D | デバイスファイルや特殊ファイルを保持します。 |
-u | コピー元とコピー先を比較し、追加・更新されたファイル・ディレクトリのみをコピーします。 |
-v | コピーしているファイル名やバイト数などの情報を表示します。 |
-z | 通信を圧縮します。 |
-4 | IPv4を使用します。 |
-6 | IPv6を使用します。 |
--delete | コピー元にない(削除された)ファイルをコピー先で削除します。コピー元とコピー先を同期します。 |
ローカルディレクトリをバックアップ
ローカルディレクトリをバックしてみます。
[vagrant@localhost ~]$ find source/ -ls 1046602 4 drwxrwxr-x 3 vagrant vagrant 4096 Nov 30 14:16 source/ 1046604 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 14:16 source/test.csv 1046605 4 drwxrwxr-x 2 vagrant vagrant 4096 Nov 30 14:16 source/dir1 1046606 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 14:16 source/dir1/test.csv [vagrant@localhost ~]$ find dest/ -ls 1046603 4 drwxrwxr-x 2 vagrant vagrant 4096 Nov 30 13:28 dest/ [vagrant@localhost ~]$
ディレクトリのバックアップなので「r」オプションが必要です。 同期内容の詳細を知りたいので「v」オプションを設定しています。
[vagrant@localhost ~]$ rsync -rv source/ dest/ sending incremental file list test.csv dir1/ dir1/test.csv sent 170 bytes received 54 bytes 448.00 bytes/sec total size is 0 speedup is 0.00 [vagrant@localhost ~]$ find dest/ -ls 1046603 4 drwxrwxr-x 3 vagrant vagrant 4096 Nov 30 20:53 dest/ 1046608 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 20:53 dest/test.csv 1046607 4 drwxrwxr-x 2 vagrant vagrant 4096 Nov 30 20:53 dest/dir1 1046609 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 20:53 dest/dir1/test.csv [vagrant@localhost ~]$ rsync -rv source/ dest/ sending incremental file list test.csv dir1/test.csv sent 167 bytes received 51 bytes 436.00 bytes/sec total size is 0 speedup is 0.00 [vagrant@localhost ~]$
一度、バックアップした後でも差分バックアップしていないので、全ファイルが同期されていることが分かります。
差分バックアップ
バックアップ元に新規にファイル(test2.csv)を追加してみます。
[vagrant@localhost ~]$ touch source/test2.csv [vagrant@localhost ~]$ find source/ -ls 1046602 4 drwxrwxr-x 3 vagrant vagrant 4096 Nov 30 20:58 source/ 1046604 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 14:16 source/test.csv 1046605 4 drwxrwxr-x 2 vagrant vagrant 4096 Nov 30 14:16 source/dir1 1046606 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 14:16 source/dir1/test.csv 1046609 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 20:58 source/test2.csv [vagrant@localhost ~]$ find dest/ -ls 1046603 4 drwxrwxr-x 3 vagrant vagrant 4096 Nov 30 20:53 dest/ 1046610 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 20:53 dest/test.csv 1046607 4 drwxrwxr-x 2 vagrant vagrant 4096 Nov 30 20:53 dest/dir1 1046608 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 20:53 dest/dir1/test.csv [vagrant@localhost ~]$
実際に差分バックアップを実施します。「u」オプションを追加します。
[vagrant@localhost ~]$ rsync -urv source/ dest/ sending incremental file list test2.csv sent 153 bytes received 32 bytes 370.00 bytes/sec total size is 0 speedup is 0.00 [vagrant@localhost ~]$ [vagrant@localhost ~]$ find dest/ -ls 1046603 4 drwxrwxr-x 3 vagrant vagrant 4096 Nov 30 21:01 dest/ 1046610 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 20:53 dest/test.csv 1046607 4 drwxrwxr-x 2 vagrant vagrant 4096 Nov 30 20:53 dest/dir1 1046608 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 20:53 dest/dir1/test.csv 1046611 0 -rw-rw-r-- 1 vagrant vagrant 0 Nov 30 21:01 dest/test2.csv [vagrant@localhost ~]$
このように今回新規に追加したtest.csvのみコピーされていることが分かります。
以上です。
【Linux】改行コードが何か調べたいときに
Teraterm等のソフトを使用してLinuxサーバにアクセスしているときに、 改行コードに何が使用されているか見れなくて調べたのでメモしておきます。
odコマンド
ファイルを8進数や16進数表記で表示します。オプションを何も指定しないと8進数で表示します。
オプション
オプション | 説明 |
---|---|
-t 出力タイプ | 出力するフォーマットを指定します。 |
-b | 8進数でバイトを出力します。「-t o2」と同じ |
-c | ASCII文字またはバック・スラッシュ付きのエスケープ文字として出力します。「-t c」と同じ |
出力タイプ | 説明 |
---|---|
c | ASCII 文字かバックスラッシュつきのエスケープ文字 |
o | 8進数(デフォルト) |
x | 16進数 |
実例
result.txtファイルの中身を参照してから、odコマンドを使用してASCIIで表示しています。 これによって改行コードが\nであることが分かります。
[vagrant@localhost unix_lessons]$ cat result.txt Sat Sep 23 12:41:24 UTC 2017 total used free shared buffers cached Mem: 1020072 375224 644848 188 21748 256216 -/+ buffers/cache: 97260 922812 Swap: 2064380 0 2064380 [vagrant@localhost unix_lessons]$ [vagrant@localhost unix_lessons]$ [vagrant@localhost unix_lessons]$ od -c result.txt 0000000 S a t S e p 2 3 1 2 : 4 1 0000020 : 2 4 U T C 2 0 1 7 \n 0000040 t o t a l 0000060 u s e d 0000100 f r e e s h a r e d 0000120 b u f f e r s 0000140 c a c h e d \n M e m : 0000160 1 0 2 0 0 7 2 3 7 0000200 5 2 2 4 6 4 4 8 4 8 0000220 1 8 8 0000240 2 1 7 4 8 2 5 6 2 1 6 0000260 \n - / + b u f f e r s / c a c 0000300 h e : 9 7 2 6 0 0000320 9 2 2 8 1 2 \n S w a p : 0000340 2 0 6 4 3 8 0 0000360 0 2 0 6 4 3 0000400 8 0 \n 0000403 [vagrant@localhost unix_lessons]$
では、以上です。ただの備忘録でした。
Streamの終端処理 抜粋
Java8で追加されたStreamの終端処理で分からないのが結構あったので勉強してみました。
stream操作は、Stream生成⇒中間処理⇒終端処理の順番で実施します。 Stream生成⇒中間処理だけ実施しても、元のリスト等には影響を与えませんし、戻り値もありません。 何か処理をしたい場合、結果を得たい場合は必ず終端処理を実施しないといけません。
気が向けばもっと増やしていくと思いますが、今回は適当にピックアップしたものを挙げています。
count
そのままわかりやすいですが、Streamの件数をカウントします。 ふつうはfilter等の中間処理と合わせて使用します。
/** * Stream終端処理 countを確認 */ @Test public void count() { // そのまま long count = IntStream.rangeClosed(1, 10).count(); System.out.println(count); // ⇒ 10 // ふつうは中間処理と合わせて使用する long count2 = IntStream.rangeClosed(1, 10).filter(i -> i > 4).count(); System.out.println(count2); // ⇒ 6 }
toArray
メソッド名そのままですがStreamを配列形式に変換して返却します。 toArrayには引数ありとなしの2パターン準備されていて、引数なしで実行した場合、Objectの配列として返却されます。 引数ありの場合、引数には引数として渡される整数のサイズの配列を返却する「generator」関数を指定する必要があります。
/** * Stream終端処理 toArrayを確認 */ @Test public void toArray() { List<String> testList = new ArrayList<String> (Arrays.asList("ABC1", "ABD2", "DBC3", "CBC4")); // 引数なしなのでObjectの配列で返却される Object[] streamToArray= testList.stream().toArray(); System.out.println(Arrays.toString(streamToArray)); // ⇒ [ABC1, ABD2, DBC3, CBC4] // Stringの配列を返却するgenerator関数を指定すると返却した配列に値が設定されて返却されます。 String[] streamToArrayFunc = testList.stream().toArray(String[]::new); System.out.println(Arrays.toString(streamToArrayFunc)); // ⇒ [ABC1, ABD2, DBC3, CBC4] // String[]::newは「i -> new String[i]」の省略です。 String[] streamToArrayFunc2 = testList.stream().toArray(i -> new String[i]); System.out.println(Arrays.toString(streamToArrayFunc2)); // ⇒ [ABC1, ABD2, DBC3, CBC4] // 当然、指定されたサイズ以外のサイズの配列を返却するとエラーとなります。 try { String[] streamToArrayFunc3 = testList.stream().toArray(i -> new String[i - 1]); } catch (IllegalStateException e) { System.out.println(e.getClass().getName()); // ⇒ java.lang.IllegalStateException } }
max, min
Streamの中から最大値、最小値を抽出します。 引数には、Comparatorを指定してください。 従来のようにcompareToで比較する関数を指定しても良いですが、Java8らしくComparator内の関数を利用するほうが分かりやすいのでおすすめです。 以下の例では、ComparatorにcomparingIntという関数を使用しています。 この関数は各要素を引数として受け取り、数値を返却して返却した値をもとに最小値を計算しています。
/** * Stream終端処理 max, minを確認 */ @Test public void maxMin() { List<String> testList = new ArrayList<String> (Arrays.asList("ABC1", "ABD2", "DBC3", "CBC4")); Optional<String> streamMax = testList.stream().max((str1, str2) -> str1.substring(3, 4).compareTo(str2.substring(3,4))); System.out.println(streamMax); ⇒ Optional[CBC4] Optional<String> streamMin = testList.stream().min(Comparator.comparingInt(str -> Integer.parseInt(str.substring(3, 4)))); System.out.println(streamMin); ⇒ Optional[ABC1] }
reduce
Streamの各要素に対してリダクション操作を実行して、その結果を返却します。 返却する値は、Streamの要素と同じ型になります。 リダクション操作ってなに?っていう人も多いと思います。実際私もそうでした。 簡単いうとリダクション操作とは、配列等の連続した値を受け取り、単一のサマリー結果を返却するものです。 いままで出てきた、count, max等がこれにあたります。 また、Javaでの以下のような操作もリダクション操作といえます。
int sum = 0; for (int i : new int[]{1, 5, 8}) { sum += i; }
reduceには引数の種類によって3種類の準備されています。
パラメータが1つ
List<String> testList = new ArrayList<String> (Arrays.asList("ABC1", "ABD2", "DBC3", "CBC4")); Optional<String> reduceValue1 = testList.stream().reduce((result, element) -> { // resultが今までの集計 // elementが今回の値 return String.join("/", result, element); }); System.out.println(reduceValue1); // ⇒ Optional[ABC1/ABD2/DBC3/CBC4]
BinaryOperatorを引数に持つ場合、2つの値を引数にもつ関数を設定します。 第一引数は、前回この関数で返却した値が入ってきます。第二引数は、Streamの要素の値が入ってきます。 今回の場合では、初回はresult = ABC1, element = ABD2、2回目はresult = ABC1/ABD2, element = DBC3が入ってきます。
パラメータが2つ
String reduceValue2 = testList.stream().reduce("FIRST", (result, element) -> { // resultが今までの集計 // elementが今回の値 return String.join("/", str1, str2); }); System.out.println(reduceValue2); // ⇒ FIRST/ABC1/ABD2/DBC3/CBC4
パラメータがひとつの場合とほぼ同じですが、こちらは第一引数に初期値を設定できます。 第一引数に指定した値に対して、第二引数に指定したアキュムレータが処理をします。 戻り値がOptinalでないのは、リストが空の場合でも第一引数に指定した値が返却されるからだと思います。
パラメータが3つ
String reduceValue3 = testList.parallelStream().reduce("FIRST", (result, element) -> { // resultが今までの集計 // elementが今回の値 return String.join("/", result, element); }, (result1, result2) -> { // result1が今までの集計 // result2が今回の値 return String.join("/", result1, result2); }); System.out.println(reduceValue3); // ⇒ FIRST/ABC1-FIRST/ABD2-FIRST/DBC3-FIRST/CBC4
パラメータが3つの場合は、パラメータが2つの場合と第一引数、第二引数は同じで、第三引数のみ違います。 第三引数は平行実行したときのみ呼び出される関数で、第二引数の結果を結合して返却します。
collect
Streamの各要素に対して可変リダクション操作を実行します。 リダクション操作とは、reduceのところで説明したとおりです。 では、可変とはなにか。 通常のリダクション操作では、単一の値を返却します。Stringとか、intとか。 可変リダクション操作とは、可変コンテナといわれるもの(CollectionとかStringBuilder等)に値を蓄積して返却します。 単一の値で返却するか、可変コンテナで返却するか返却するものの違いがリダクション操作と可変リダクション操作の違いです。
collect関数の説明に戻ります。 collect関数は、引数にCollectorを取る場合と、Supplier, accumulator, combinerの3つを取る場合の2種類存在します。 まずは、Collectorを取る場合です。
/** * Stream終端処理 collect Collectorを確認 */ @Test public void collect1() { List<String> testList = new ArrayList<String> (Arrays.asList("ABC1", "ABD2", "DBC3", "CBC4")); // Streamをリストに変換します。 List<String> list = testList.stream().map(s -> s.substring(0, 2)).collect(Collectors.toList()); System.out.println(list); // ⇒ [AB, AB, DB, CB] // groupingByで指定した関数が返却する値をキーにMapを返却します。 Map<String, List<String>> groupingMap = testList.stream().collect(Collectors.groupingBy(s -> s.substring(0,1))); System.out.println(groupingMap); // ⇒ {A=[ABC1, ABD2], C=[CBC4], D=[DBC3]} }
このように簡単に、可変リダクションを実現できます。 Collectorsには、便利な関数がたくさん用意されています。また、時間があればこちらも紹介したいと思います。
次に、Supplier, accumulator, combinerの3つを引数に取る場合です。
/** * Stream終端処理 collectを確認 */ @Test public void collect2() { List<String> testList = new ArrayList<String> (Arrays.asList("ABC1", "ABD2", "DBC3", "CBC4")); Map<String, List<String>> groupingMap2 = testList.stream().collect(HashMap<String, List<String>>::new, (map, s) -> { String key = s.substring(0, 1); List<String> innerList = map.getOrDefault(key, new ArrayList<String>()); innerList.add(s); map.put(key, innerList); }, (map1, map2) -> {}); System.out.println(groupingMap2); // ⇒ {A=[ABC1, ABD2], C=[CBC4], D=[DBC3]} Map<String, List<String>> groupingMap3 = testList.parallelStream().collect(HashMap<String, List<String>>::new, (map, s) -> { String key = s.substring(0, 1); List<String> innerList = map.getOrDefault(key, new ArrayList<String>()); innerList.add(s); map.put(key, innerList); }, (map1, map2) -> {}); System.out.println(groupingMap3); // ⇒ {A=[ABC1]} 値は変わる可能性があります。 Map<String, List<String>> groupingMap4 = testList.parallelStream().collect(HashMap<String, List<String>>::new, (map, s) -> { String key = s.substring(0, 1); List<String> innerList = map.getOrDefault(key, new ArrayList<String>()); innerList.add(s); map.put(key, innerList); }, (map1, map2) -> { map2.forEach((key, list) -> { List<String> innerList = map1.getOrDefault(key, new ArrayList<String>()); innerList.addAll(list); map1.put(key, innerList); }); }); System.out.println(groupingMap4); // ⇒ {A=[ABC1, ABD2], C=[CBC4], D=[DBC3]} }
さきほどのgroupingByを使った例と同じ値を返却します。 各引数は以下の意味を表します。 Supplier: collect関数で返却する可変コンテナを返却する関数を定義します。 accumulator: 第一引数にSupplierで返却したコンテナ、第二引数にStreamの各要素がわたってきます。 この関数で返却するコンテナに値を設定します。 combiner: 並列処理を実施しない場合、なにも設定しなくて良いです。 並列処理が行われたときに、第二引数で返却された値を結合するための処理を定義します。
以上で、終端処理の説明を終わります。 間違っているところがあれば教えてください。
Java8の日付
Java8になってLocalDate, LocalTime, LocalDateTimeクラスが追加されましたね。 おかげで面倒だった日付の操作が一気に簡単になったので紹介したいと思います。
現在の時間
LocalDateTime ldt = LocalDateTime.now();
これで簡単に取得できます。
日付を数値で指定してインスタンスを作成する
年、月、日付、時間、分、秒、ナノ秒それぞれ数値で指定してインスタンスを作成できます。
LocalDateTime ldt = LocalDateTime.of(2017, 12, 10, 23, 59, 59, 1);
当然、月の場合は13以上、日付はその月に存在しない日を指定したらエラーとなります。
LocalDateTime.of(2017, 13, 10, 23, 59, 59, 1); // ⇒ java.time.DateTimeException LocalDateTime.of(2017, 12, 32, 23, 59, 59, 1); // ⇒ java.time.DateTimeException LocalDateTime.of(2017, 12, 10, 24, 59, 59, 1); // ⇒ java.time.DateTimeException
日付を文字で指定してインスタンスを作成する
この機能が個人的に一番うれしいです。今までよりずっと楽にパースできるようになりました。 まずは、DateTimeFormatterクラスを使用して、パースしたい日付のフォーマット、ロケール等を指定してフォーマッターを作成します。
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss", Locale.JAPANESE);
作成したフォーマッターを使用して、日付文字列をパースします。
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss", Locale.JAPANESE); LocalDateTime ldt = LocalDateTime.parse("2017/10/15 13:53:15", dtf);
当然、存在しない日付を指定するとエラーとなります。
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss", Locale.JAPANESE); LocalDateTime ldt = LocalDateTime.parse("2017/10/32 13:53:15", dtf); // ⇒ java.time.DateTimeException: Invalid value for DayOfMonth
これは、Datetimeformatterがもつリゾルバ・スタイルという属性により制御されています。 リゾルバ・スタイルとは、日時文字列を解析した際の値が範囲外(10月なら32日以降)の場合に、それを解決する方法を決定する属性です。デフォルトがSMART(賢い)で、他にLENIENT(寛大)、STRICT(厳密)があります。 以下、各設定における動作です。
- SMART(賢い):
明らかに許容範囲を超えている場合はエラーになる。例えば13月や32日は絶対にありえないのでエラー。 31日より少ない月では、31以下で本来ありえない日を指定すると、その月の末日になる。
例
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss") .withResolverStyle(ResolverStyle.SMART); LocalDateTime ldt = LocalDateTime.parse("2017/11/31 23:16:10", dtf); // ⇒ 2017/11/30T23:16:10
このように31で指定しても30に丸み込まれる ちなみに、日付以外の項目が限界値を超えてもエラーとなる。 23時ではなく24時を指定してもエラー。60分を指定してもエラー。
- LENIENT(寛大):
許容範囲を超えている場合は、本来の月末日を超えて、超過分を加算した日付になる。
例
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss") .withResolverStyle(ResolverStyle.LENIENT); LocalDateTime ldt = LocalDateTime.parse("2017/11/33 23:16:10", dtf); // ⇒ 2017/12/03T23:16:10 LocalDateTime ldt = LocalDateTime.parse("2017/13/33 24:61:61", dtf); // ⇒ 2018-02-03T01:02:01
- STRICT(厳密):
その日時に許されないものは全てエラーになる。 書式「yyyy」は、厳密には暦(ERA。和暦の場合は昭和とか平成とか)に対する年なので、ERAが指定されていない場合はエラーになる。 書式「uuuu」はERAと無関係な年を表す。
例
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd G HH:mm:ss") .withLocale(Locale.ENGLISH) .withResolverStyle(ResolverStyle.STRICT); LocalDateTime ldt = LocalDateTime.parse("2017/11/30 AD 23:16:10", dtf); // ⇒ 2017/11/30T23:16:10 DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("uuuu/MM/dd HH:mm:ss") .withResolverStyle(ResolverStyle.STRICT); LocalDateTime ldt2 = LocalDateTime.parse("2017/11/30 23:16:10", dtf2);
英語の月のパース
ロケールを変更するだけでできます。
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MMM/dd HH:mm:ss", Locale.ENGLISH); LocalDateTime ldt = LocalDateTime.parse("2017/Oct/15 13:53:15", dtf);
ただ、この場合、月を「oct」のように小文字にするとエラーとなってしまいます。 この場合どうするか。 ちょっとわからないです。また、調べてから載せます。
計算方法
LocalDateは、日付の加算、減算が非常に簡単にできるようになっています。 みたとおりの機能なので、説明は省きます。
LocalDateTime ldt = LocalDateTime.now(); ldt.plusYears(1); ldt.plusMonths(1); ldt.plusDays(1); ldt.plusHours(1); ldt.plusMinutes(1); ldt.plusSeconds(1); ldt.minusYears(1); ldt.minusMonths(1); ldt.minusDays(1); ldt.minusHours(1); ldt.minusMinutes(1); ldt.minusSeconds(1);
こんな感じでしょうか。また、使用することがあれば、追加していきます。
pythonをはじめる。自分の意思表示みたいなもの。
はてなブログ始めます。
私は、社会人になってから、Java、Javascript、sqlを使用するプロジェクトばかり担当させられていました。 ここにきて、今まで経験していない言語をなんかやりたいなーと思い、今はやっているpythonを勉強しようと決心しました。 何を作るのか、決まっていませんが機械学習を利用したアプリを作れたらなと思っています。 たとえば、株価予想とか。。。 Raspberry piを使用した何かか。。
とくに決まっていませんが、まずはpythonを使用できるようになるまで、備忘録を書いていこうと思います。
まず、pythonとは?
世界中で使用されているスクリプト言語のひとつ。 スクリプト言語って何?と思う人がいるかもしれないが、簡単にかけて実行できるプログラムっていうイメージでよいかな。 詳しく言うなら、事前にコンパイルが必要でない言語。javaScriptとかphpとかもスクリプト言語にあたる。
特徴
シンプルで読みやすいコードが書ける 同じような機能をもつプログラムは同じようなコードになると言われている。 これはホントにありがたいことだと思う。 基本的にプログラムを書くときには、より単純によりきれいに書くべきなので、それが自然とできるってこと。 そのため、初心者にも結構進められたりするみたい。
数学に関連する分野が得意 数値処理が高速で化学計算用、統計用、機械学習等のライブラリが豊富なので数学処理の分野に向いている
インデント ブロック構造をインデントで表現する。Javaをやっていた私にとっては結構衝撃的です。 ただ、インデントが強制されるので可読性が上がり、メリットはかなりある。 例)
if (true) { ~ // ここにtrueのときの処理を記述 }
if True : ~ # ここにtrueのときの処理を記述