【他プログラミング言語修得者向け】Python 要点キャッチアップ10点

# Overview
Pythonは、シンプルで習得がしやすいオブジェクト指向言語として有名である。
他言語修得者向けに、Python独自の要素を10点独断で選別したので、それを記載する。

## 1. 改行の ";" が不要
多くの言語の共通ルールである「改行時は;」について、Pythonでは不要。
とはいえ、改行として認識自体はされるため、以下の様なコードを実行してもエラーにはならず、従来通りの挙動をする。

```python
>>> print("1"); print("2")
1
2
```

## 2. インデントがブロックを表す
他言語において、インデントはコードの可読性を高めるための要素で、挙動に影響はしなかった。
しかし、Pythonではインデントを使ってブロックを表現する。

```python
if x > 0:
  print("positive") # if文内
print("always")     # if文外
```
上記のコードでは、xが0以上の場合は"positive","always"の両方を表示、それ以外の場合でも"always"を出力する。


また、 以下の様に適切なインデントがない場合は`IndentationError: expected an indented block` が発生する。

```python
if x > 0:
print("positive")   # IndentationError発生
```

## 3. シングルクォーテーション、ダブルクォーテーションが同義
Pythonにおいては、これらの間に違いは存在しない。以下のコードは、いずれも同様に挙動となる。

```python
>>> print('single')
single
>>> print("double")
double
```

仮に文字列中に`'`を入れる場合は、表記は異なる。

``` 
>>> print('It\'s single') # \ でエスケープ
It's single

>>> print("It's double")  # 文字列に含まれるクォーテーション
It's double
```

同じコード内で表記を統一する必要もないので、単語の場合はシングル、文章の場合はダブルなど、一定ルールを設けることも可能。

```python
s = 'single'
w = "It's a double!"
```


## 4. 変数宣言と型
`var` や型指定は不要。 `変数名 = 値` の書式で 数値、文字列、真偽値 を格納できる。
ただし、値から型を推測するため、初期値が必要となる。
以下の表記は全てエラー。

```python
# 型指定は不要
int a = 1
        ^
SyntaxError: invalid syntax


# var の記述も不要
var a = 1
        ^
SyntaxError: invalid syntax


# 初期値がない場合もエラー
a
NameError: name 'a' is not defined    
```

また、一度宣言した変数に、全く違う型の値を代入することができる。その場合、変数の型も同時に変わる。

```shell
>>> a = 100
>>> type(a)
<class 'int'>

>>> a = "text"
>>> type(a)
<class 'str'>

>>> a = True
>>> type(a)
<class 'bool'>
```

## 5. その他よく使うデータ型
Pythonでは数値、文字列、真偽値に加えて、 **リスト、タプル、セット、辞書型** がある。
いずれも複数データを格納するデータ型で、特徴は以下の通り。

| データ型名 | 特徴 | 宣言の仕方 |
| --- | --- | --- |
| リスト(list) | 追加・重複の制限なし | [val1, val2, ...] |
| タプル(tuple) | 宣言後の追加・更新を許可しない, パフォーマンスが高い | (val1, val2, ...)
| セット(set) | 同値の重複を許可しない | {val1, val2, ...}
| 辞書型(dict) | key-value 形式 | {key1: val1, key2: val2, ...}|


```python
### リスト型
list1 = [1,2,3]
type(list1)    # -> <class 'list'>
print(list1)   # -> [1, 2, 3]
print(list1[0]) # -> 0
list1.append(4)
print(list1)   # -> [1, 2, 3, 4]

### セット型
set1 = {1,2,3,3}
type(set1)  # -> <class 'set'>
print(set1) # -> {1, 2, 3}
set1[0] = 9 # -> TypeError: 'set' object does not support item assignment
set1.add(4)
print(set1) # -> {1, 2, 3, 4}

### タプル型
tuple1 = (1,2,3)
type(tuple1)  # -> <class 'tuple'>
print(tuple1) # -> (1,2,3,3)
tuple1[0] = 9 # -> TypeError: 'tuple' object does not support item assignment

### 辞書型
dict1 = {"a": 123, "b": 456, "c": 789}
type(dict1)  # -> <class 'dict'>
print(dict1) # -> {'a': 123, 'b': 456, 'c': 789}
dict1["d"] = 0
print(dict1) # -> {'a': 123, 'b': 456, 'c': 789, 'd': 0}
```
タプルの用途としては、統計値などの一度宣言した値や順番を変更したくないとき、または変更する必要がないときに利用する。
メモリを圧迫しないため、パフォーマンス向上につながる。

また、これらは相互に変換することも可能。ただし、構成によってはエラーになる。

```python
list1 = [1,2,3]
print(tuple(list1)) # -> (1, 2, 3)
print(set(list1))   # -> {1, 2, 3}
list2 = [["a", 123], ["b", 456], ["c", 789]]
print(dict(list2))  # -> {'a': 123, 'b': 456, 'c': 789}
```

## 6. スライス操作
先のデータ型もそうだが、他言語では「配列」と呼ばれる様な複数要素をまとめて１つの変数で扱えるデータ型を、Pythonでは **シーケンス型** と呼ぶ。
具体的には以下が該当。

| 型 | 解釈 | 
| --- | --- |
| 文字列(string) | 連続した文字 |
| レンジ(range) | 連続した数値 |
| バイト(bytes) | 連続したバイト |
| リスト(list) | 連続したデータ, あらゆるデータを扱える |
| タプル(tuple) | 要素追加・更新のできない連続したデータ | 
| セット(set) | 重複を許可しない連続したデータ |

これらに対して、一部分を切り取ってコピーを返す**スライス操作**がPythonでは利用できる。
指定の際は`seq[start:stop:step]` の様に指定する。値を指定しなかった場合はデフォルト値が適用されるが、全て未指定にはできない。

| 引数| 指定する値| デフォルト |
| --- | --- | --- |
| start | 切り取り視点インデックス | 0 |
| end | 切り取り終点インデックス | 要素数に等しい値 |
| step | 切り取る際のステップ数<br>負数の場合は逆順にする | 1 |

インデックスは、 [Pythonチュートリアル](https://docs.python.org/ja/3/tutorial/introduction.html#strings) の考え方がわかりやすい。
つまり、「**インデックスは要素と要素の境界を指し、最初の要素の左端が0**」ということである。
また、マイナス指定インデックスは一番最後の文字を指すインデックスが-1, 以降前に戻る度に負の値が増加する。

```
 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1
```

上記を踏まえて、以下の様に利用する。

```python
str = "Python"
print(str[3:])   # -> "hon"
print(str[:3] )  # -> "Pyt"
print(str[::-1]) # -> "nohtyP"
print(str[::2])  # -> "Pto"
```


## 6. 制御文全般の留意点
全体的な留意点は以下。

- 条件式で `()` は不要
- 末尾に`:` を記入する

例えば、if 文の使い方は以下。他言語と比べて大きな違いはないが、`elif` の表記だけやや特殊かも。

```python
### if文
if x > 0:
  print("positive")
elif x < 0:
  print("negative")
else:
  print("zero")
```


## 7. for文はシーケンスと組み合わせて柔軟に回せる
in 以下で、先に述べたシーケンス型を指定することでその要素を回すことができる。

```python
list1 = [1,2,3]
for val in list1:
  print(val)

1
2
3
```
シーケンス型の変数を事前に使っていない場合は、range関数で連続した数字のシーケンスを生成できるので便利。

```python

# 引数1つの場合は0始まり
for i in range(3):
  print(i)

0
1
2

# 引数2つの場合は始点を変更できる
for i in range(1, 4):
  print(i)

1
2
3

# 引数3つの場合は間隔を変更できる
for i in range(1, 8, 2): 
  print(i)

1
3
5
7
```


## 8. 終了を伴う処理をwith文で簡易化できる
Python の特徴的な構文に、**with** が存在する。
一般的に他言語で「ファイルの読み書き」や「通信処理」を行う場合は、開始と終了を明確に宣言する必要があった。
しかし、Pythonではwith文と同時に開始処理を宣言することで、インデントを抜けた際に自動で終了処理を行ってくれる。

ここでは、ファイルの読み書きを例としてみる。

```python
# ファイルの読み込み
with open("read.txt", "r") as file1:
    print(file1.read())

# ファイルの書き込み
with open("write.txt", "w") as file2:
    print(file2.write())
```

もちろん、以下の様に入れ子で宣言することも可能。

```python
# ファイルから読み込んだ内容を別ファイルに書き込む
with open("reaad.txt", "r") as file1:
    with open("write.txt", "w") as file2:
        file2.write(file1.read())
```


## 9. 複数の値を返す関数を作成できる
まず、python における関数定義は以下の様に`def`を使って行う。

```python
def double(x):
  return x * x

print(double(10)) # -> 100
```

この際に、返り値をタプル、またはカンマ区切りで複数指定することができる。カンマ区切りが可能なのは、Python においてカンマで区切られた値は丸括弧を省略したタプルとみなされるため。
このとき、この複数の返り値を異なる変数に格納することも可能。

```python
def test():
  return "a", 123, True # return ("a", 123, True) と同義

print(test())           # -> ('a', 123, True)

a, b, c = test()
print(a)                # -> 'a'
print(b)                # -> 123               
 print(c)                # -> True
```

## 10. ライブラリの利用はimport
Python は、 デフォルトで利用できる組み込み関数に加えて、適宜`import`を実行することで各種ライブラリを簡単に利用することができる。
import宣言はプログラムの冒頭で宣言し、以下の順番で記述することがPEP8では望ましいとされている。

1. 標準ライブラリ
2. サードパーティライブラリ
3. ローカルライブラリ（自作のライブラリ）
グループ間は空白行で区切り、同一グループ内はアルファベット順とすることが多い。

```python
# 標準ライブラリ
import math
import os
import sys

# サードパーティライブラリ
import Requests

# 自作ライブラリ
import my_package1
import my_package2
```
 
また、`import` と一緒に `as`, `from`もよく使われる。
as を使うことで、importしたモジュールやオブジェクトに対して別名をつけることができる。
例えばmath を m, numpy を np とするのはよくある。

```python
import math as m
import numpy as np

print(np,array([1,2], [100,200])) # -> array([[1, 2],[100, 200]])
print(m.pi)                       # -> 3.141592653589793
```

fromは、大別して以下2種類のいずれかの用法となる。
ここで、ライブラリの階層は **パッケージ > モジュール > オブジェクト** の構造となっていることを踏まえると、上位階層から下位階層を取得するイメージとなる。

* `from <モジュール名> import <オブジェクト名>`
* `from <パッケージ名> import <モジュール名>`



めちゃくちゃざっくり言うと、

* パッケージ = ディレクトリ
* モジュール = クラスファイル
* オブジェクト = 各種関数、定数
と置き換えて認識してもよい。


例えば、円周率πをよく使うなら、オブジェクトpiを指定してimportするとよい。

```python
from math import pi # math クラスの pi オブジェクトをインポート
print(pi)           # math 指定なしに、そのまま利用できる。
```

# 終わりに
10項目もあると結構な量になるが、ここにある内容を理解できればまずはPython初心者卒業といったところだろうか。
あとは各種汎用ライブラリ独自の用法を適宜把握できれば、コーディングはスイスイできるはず！