Python基本文法メモ

### ブロック

- Javaなどの`{}`のようなブロックはインデントで表現する。

### コメント

- コメントは `#` 。 3重のクォーテーションで、複数行コメントとして使える。

### 変数

- 変数の作成 `変数名 = 値`
- 変数名は、 `sample_color` のように、`_` で区切るのが一般的。
- constのような定数は基本的にない。`CONST_VALUE=100` のように大文字、アンダースコアで命名する。
- `type()`関数で、型を調べられる。
- `id(オブジェクト)` でオブジェクトのid番号を調べられる。

### 数値型

- Pythonの数値型は、整数型(int)、浮動小数点型(float)、複素数型(complex)の３種類。
- リテラル、`5`はint、`5.0`はfloat、`0xff = 255`は１６進数、`0o23 = 19`は８進数、`0b1111 = 15`は２進数。
- `float("160.5")` で文字列型をfloat型に変換できる。
- 指数表現 `9.5e3 == 9.5 * 10 ** 3`
- `int("5")`で文字型から整数型に変換。`int("FFF",16)`で１６進数を整数型に変換。
- `str(数値)`で数値型から文字型に変換する。`hex()` `oct()` `bin()`を使うと、それぞれ１６進数、８進数、２進数の文字型に変換する。

### 演算子

- 四則演算は、`+ - * /`
- べき乗は、`**`
- 切り捨て除算、`//`
- 剰余、`%`
- 代入演算子は、 `+= -= *= /= //= %=` などが使える。 `++ --` は使えない。

### 文字列型

- 文字列型は、シングルクォーテーションかダブルクォーテーションで囲む。`\`でエスケープ。
- 複数の行の文字列を記述するには、３重クオーテーションで囲む。
- 文字列は、`+` で結合できる。


### print関数、input関数

- `print(引数１, 引数２, ...)` で画面表示。改行しないようにする `print(引数１, 引数２, ... , end="")`
- キーボードから入力するには、 `str = input("入力してください：")` のようにして、文字列型が返却される。

### シーケンス型（リスト、タプル、文字列、など）

- `height = [180, 165, 159, 171, 155]` のようにしてリスト型を作成する。
- `height[0]` のようにして、リスト型の中身を取り出す。
- `height[1] = 182` のようにして、中身を変更できる。
- `height[-1]` で一番右の値を取り出す。
- `len(height)` でリストの長さを返す。
- `height_tuple = (180, 165, 159, 171, 155)` のようにしてタプル型を作成する。タプルは値が変更不可なリスト。`()` は省略可。値の取り出し方はリストと同じ。
- `list()` `tuple()` でリストとタプルの相互変換可能。

### import

- `import モジュール名` でモジュールのインポートをする。
- `モジュール名.コンストラクタ` を呼び出すことにより、クラスのインスタンスを作成する。
- `インスタンス変数.メソッド名（引数, ...）` でメソッドを呼び出す。

```python
import calendar
cal = calendar.TextCalendar()
cal.prmonth(2016, 1)
```

- `from モジュール名 import クラス名1, クラス名2, ...` と指定すれば、クラスを呼ぶ時のモジュール名を省略できる。

```python
from calendar import TextCalendar
cal = TextCalendar()
cal.prmonth(2016, 1)
```

- 関数のモジュールをインポートする（クラスのインポートと同じ）
- `import モジュール名` の時、 `モジュール名.関数名` で関数を呼び出せる。
- `from モジュール名 import 関数名1, 関数名2, ...` の時は、関数名を直接呼び出せる。
- `from モジュール名 import *` で全ての関数を読み込む。

### 乱数の利用

- `import random`
- `randint(0,3)` で、０以上３以下の整数の乱数を生成する。
- `randrange(3)` で。０以上３未満の整数の乱数を生成する。

### if文

```py
if 条件式A:
  処理１
elif 条件式B:
  処理２
else:
  処理3
```

- 論理演算子は、`and` `or` を使う。
- 条件式は、 `3 <= month < 5` のように書ける。
- リストやタプルは、`in` で含まれるかを判定できる `3 in [1, 2, 3, 4]`
- `not in` で含まれないかを判定できる `3 not in [1, 2, 3, 4]`
- `in` `not in` は文字列にも使える `"日" in "月火水木金土日"`
- Pythonには、switch文はない。
- 以下のように３項演算子を使える。

```python
値１ if 条件式 else 値２

msg = "こんにちは" if hour < 18 else "こんばんは"
```

### ループ処理

- Pythonに、do〜whileループはない
- range([開始,] 終了[, ステップ])

```python
# for文
for l in list:
  処理

# １０回繰り返す(i=1〜9)
for i in range(10):
  処理

# rangeオブジェクトをリストに変換
l = list(range(0, 31, 10))
# i=[0, 10, 20, 30]

# while
while 条件式:
  処理
```

- enumerate()関数を使うと、インデックスと要素のペアが取り出せる。

```python
countries = ["フランス", "アメリカ", "中国" , "ドイツ" , "日本"]
for index, country in enumerate(countries):
  print(str(index + 1) + ":", country)
```

- zip(リスト1, リスト2, ...)関数を使うと、複数のリストの値を、一番短いリストの要素がなくなるまで、タプルとして順に取り出せる。

```python
weekday1 = ["Sun", "Mon", "Tue" , "Wed" , "Thu"]
weekday2 = ["日", "月", "火" , "水" , "木", "金", "土"]
for (eng, jap) in enumerate(weekday1, weekday1):
  print(eng + ":" + jap)
```

- elseで、forループが終了した時の処理を書ける。ただし、breakで抜けた時は実行されない。

```python
for 変数 in イテレート可能なオブジェクト:
  ループ本体
else:
  完了した時に実行されるブロック
```

### 例外処理

- exceptで、例外を指定しないと、任意の例外を捕まえることができる。
- exceptで、タプルを使って、複数の例外を指定することができる。
- elseで、例外が発生しなかった場合の処理を記述できる。

```python
try:
  例外が発生する可能性がある処理 
except 例外:
  例外が発生した場合の処理
else:
  例外が発生しなかった場合の処理
```

### 文字列の活用

- `"python".upper()` で大文字を出力する。
- `"python".lower()` で小文字を出力する。
- `"python".count("y")` で指定した文字列の出現回数をカウントする。
- `"/python/".startswith("/")` で指定した文字列で終わるかどうかをTrue/Falseで返す。
- `"/python/".endswith("/")` で指定した文字列で終わるかどうかをTrue/Falseで返す。
- `"python".find("t")` で指定した文字列が含まれるかどうかをTrue/Falseで返す。
- `",".join(リスト)` で指定した文字列とリストを連結して返す。
- `"Python".replace（"n", "a")  # Pythoa`
- `"Apple Orange Pineapple".split(" ")  # ['Apple', 'Orange', 'Pineapple']` セパレータで区切る。
- `"Pineapple"[4:9]  # apple` 0から始まる４番目から9−１=８番目を取り出す。
- `[開始値：]`、`[:終了位置]` で開始値または終了位置を省略できる。
- `"月" in "月火水木金土日" # True` `in`で含まれるかどうか調べる。
- `"abcde".find("d"))  # 3` `find()` で文字列が見つかった位置を返す。みつからなければ-1を返す。
- `"こんにちは{}の世界へようこそ{}月{}日".format("Python", 12, 24) # こんにちはPythonの世界へようこそ12月24日` formatで、`{}`の中に文字や数字を埋め込むことができる。
- `"こんにちは{2}の世界へようこそ{0}月{1}日".format(12, 24, "Python") # こんにちはPythonの世界へようこそ12月24日` {}の中の数字で、順番を指定することができる。
- `{引数の番号:.桁f}` で小数点の桁数を指定できる。
- `{引数の番号:,}` で３桁区切りでカンマを挿入できる。

### リストやタプルの基本操作

- `+` でリストを結合する。 `["春", "夏"] + ["秋", "冬"]  # ['春', '夏', '秋', '冬']` （新たなリストを作成する）
- `*` でリストを繰り返す。 `["春", "夏"] * 3  # ['春', '夏', '春', '夏', '春', '夏']` （新たなリストを作成する）
- `リスト[０から始まる開始位置:０から始まる終了位置の次の番号]` で要素を取り出す。
- `[::ステップ数]` でステップ数ごとに要素を取り出せる。
- `探したい要素 in リスト` で、存在するかどうかをTrue/Falseで返す。`not in` で存在しないことを返す。
- `リスト.index(探したい要素)` で順番を返すが、見つからない場合は`ValueError`例外を返す。
- `リスト[インデックス] = 値` でリストの値を変更する。インデックスが見つからなければ`IndexError`例外が発生する。
- `リスト.append(追加したい値)` でリストに値を追加できる。リストを追加した時は1つの要素として追加され、リストが入れ子になる。
- `リスト.remove(削除したい値)` で、値に一致する最初の要素を削除できる。（一致しても２番目以降は削除されない）
- `del リスト[インデックス]` で、指定したインデックスの要素を削除できる。
- `del リスト[1:4]` で、インデックス１〜３が削除できる。
- `max(リスト) min(リスト) sum(リスト)` で、それぞれ最大、最小、合計値を返す。
- リスト同士が同じ値かを調べるには、`==` 演算子を使う。オブジェクトか同じかどうかは、`is` 演算子を使う。
- `リスト.reverse()` で、そのリスト自身を反転させる。

### コマンドライン引数

- コマンドライン引数は、`sys.argv` からリストが取れ、０番目は実行プログラムファイル名で、１番目〜から取得する。

```python
import sys
# インデックス番号を取得するためにenumerate()関数を使用する
for i,a in enumerate(sys.argv):
    print(i,a)
```

### 辞書

- 辞書 `{キー1:値1, キー2:値2, キー3:値3, ...}`
- 要素数は、`len(辞書)`
- 辞書のキーにタプルが使える `{("日本","東京都"):"千代田区",("日本","千葉県"):"船橋市",("日本","埼玉県"):"川口市"}`
- 値を取り出す `辞書[キー]`
- 値を更新する `辞書[キー] = 新しい値`
- ペアを追加する `辞書[追加するキー] = 追加する値`
- ペアを削除する　`del 辞書[キー]`
    - 存在しないキーを指定すると、 `KeyError` 例外が発生する
- キーが存在するかどうか調べる `キー in 辞書`
- for文などで使用する（イテレート）
    - キーの一覧を取得する `辞書.keys()`
    - 値の一覧を取得する `辞書.values()`
    - ペアの一覧を取得する `辞書.items()` 
- 文字列の中に出てくるフルーツの数をカウントするプログラム

```python
fruits = "apple orange strawberry banana orange apple grape strawberry apple"

count = {}

fruits_list = fruits.split(" ")

for f in fruits_list:
    if f in count:
        count[f] += 1
    else:
        count[f] = 1

for k, v in count.items():
    print(k, v)

# apple 3
# orange 2
# strawberry 2
# banana 1
# grape 1
```

### 集合(set)

- 重複を許さないリストは、集合（set)で、 `{要素1, 要素2, 要素3, ...}` で作る。
- `set(リスト)` でリストから集合が作ることができる、重複はなくなる。
- `集合.add(追加する要素)` で要素を追加する。
- `集合.remove(削除する要素)` で要素を削除する。
- `集合.clear()` で全ての要素を削除する。
- `in` で含まれるか調査する。
- `set1 | set2` で両方を含む、新たな集合を返す。
- `set1 & set2` で両方に共通した要素をもつ、新たな集合を返す。
- `set1 - set2` でset1に含まれ、かつset2に含まれない、新たな集合を返す。
- `set1 ^ set2` でset1とset2のどちらか一方に含まれる、新たな集合を返す。

### 内包表記

- `[式 for 変数 in イテレート可能なオブジェクト]` リストを作成する

```python
l = [num ** 2 for num in range(0, 21, 2)]
# [0, 4, 16, 36, 64, 100, 144, 196, 256, 324, 400]

dolls = [1,55,243,445,178]
rate = 106
yens = [d * rate for d in dolls]
# [106, 5830, 25758, 47170, 18868]
```

- `if`の追加 `[式 for 変数 in イテレート可能なオブジェクト if 条件式]`

```python
address = ["東京都千代田区", "東京都世田谷区", "埼玉県さいたま市", "神奈川県横浜市", "東京都足立区"]
# 東京都のみ取り出す
tokyo = [a for a in address if a.startswith("東京都")]
# ['東京都千代田区', '東京都世田谷区', '東京都足立区']

people = [("鈴木", "女"), ("山田", "男"), ("高橋", "女"), ("佐藤", "男")]
# 男のみの名前を取り出す
man = [p[0] for p in people if p[1] == "男"]
```

- 辞書の内包表記 `{キー:値 for 変数 in イテレート可能なオブジェクト}`

```python
en = ["apple", "orange", "cherry", "banana"]
jp = ["りんご", "オレンジ", "さくらんぼ", "バナナ"]
fruits = {k: v for k, v in zip(en, jp)}
# {'apple': 'りんご', 'orange': 'オレンジ', 'cherry': 'さくらんぼ', 'banana': 'バナナ'}
```

- 集合の内包表記 `(式 for 変数 in イテレート可能なオブジェクト}`
- タプルの内包表記はない。

### 関数

```python
def 変数名(引数1, 引数2, ...):
  処理
  return 戻り値
```

- キーワード引数 呼び出し側：`f(p1=100, p2=200)`
- デフォルト引数 関数定義側：`f(a=1, b="empty"):`
- 関数に渡された引数は、関数内で変更しても呼び出し側には反映されないが、関数にミュータブルな引数を渡すと変更が反映される（appendなどの破壊的メソッドのみ）

```python
def change(a):
    a.append(4)

a = [1, 2, 3]
change(a)
print(a)
# [1, 2, 3, 4]
```

### 変数のスコープ

- グローバルスコープ 関数の外部で作成された変数 プログラム全体で有効
- ローカルスコープ 関数の内部で作成された変数 
    - 同じ名前がある場合は、ローカルスコープが優先されるため、関数内でグローバル変数に代入したい場合は、 `global グローバル変数名` で定義する必要がある。

### 可変長引数

- 可変長引数を定義する場合は、変数名の前に `*` をつける。 `def(*objects, sep = ''):` 可変長変数の後ろの引数は、キーワード引数にする。（どこまでが可変長引数かわからないため）
- 可変長引数はタプルとして受け取る。


### キーワード引数を辞書として受け取る

- 仮引数名の前に `**` をつけると、キーワード指定された任意の数の引数を辞書として受け取れる。

```python
def dic(**a):
    print(a)

dic(height=100, width=80, depth=50)
# {'height': 100, 'width': 80, 'depth': 50}
```

 ### 関数もオブジェクト

- `hello(a)` は、 `my_func = hello` と代入すれば、 `my_func(a)` として呼び出し可能。

### ラムダ式

- `lambda 引数1, 引数2, 引数3, ... : 処理`
- キーワード引数やデフォルト値、可変長引数、も使用可。

 ```python
smaller = lambda n1, n2: n2 if n1 > n2 else n1
print(smaller(9, 2)) # 2
print(smaller(1, 11))  # 1

ave = lambda *n : sum(n) / len(n)
print(ave(1, 5, 10, 50, 1000, 5000, 10000))  # 2295.1428571428573
```

### リストの要素をまとめて処理する `map()`関数

- `map(関数, リスト)` mapオブジェクトで返す。（イテレート可能なオブジェクト）
- `list(map(関数, リスト))` リストで返す

```python
def cm(inch): return inch*2.54

inches = map(cm, [1, 2, 5, 10, 100])

for i in inches:
    print(i)

print(list(map(cm, inches))) # [2.54, 5.08, 12.7, 25.4, 254.0]
# 以下のように書いても同じ
print(list(map(lambda inch: inch*2.54, [1, 2, 5, 10, 100]))) # [2.54, 5.08, 12.7, 25.4, 254.0]
# 内包表記
print([n*2.54 for n in [1, 2, 5, 10, 100]]) # [2.54, 5.08, 12.7, 25.4, 254.0]
```

### リストの値をフィルタリングする `filter()`関数

- `filter(関数, リスト)` 関数でTrueとなる要素をイテレート可能なオブジェクトで返す

```python
print(list(filter(lambda n: n % 2 == 0, range(0, 10)))) # [0, 2, 4, 6, 8]
# 内包表記
print([n for n in range(0, 10) if n % 2 == 0]) # [0, 2, 4, 6, 8]
```

### リストをソートする

- `リスト.sort()` でそのリスト自身をソートする。`リスト.sort(reverse=True)` でそのリスト自身を逆順ソートする。
- `ソートされたリスト = sorted(リスト)` でソートしたリストを返す。
- `ソートされたリスト = sorted(ソートする前のリスト, key=str.upper)` 大文字としてソートする
- `ソートされたリスト = sorted(key=関数)` 関数の結果でソートする

### 辞書をソートする

```python
names = {"taro": 2, "jiro": 4, "saburo": 1, "shiro": 3}
# 値でソートする
print(sorted(names.items(), key=lambda n: n[1])) # [('saburo', 1), ('taro', 2), ('shiro', 3), ('jiro', 4)]
# 値でソートする（逆順）
print(sorted(names.items(), key=lambda n: n[1], reverse=True)) # [('jiro', 4), ('shiro', 3), ('taro', 2), ('saburo', 1)]
```

### ジェネレータ関数

- returnの代わりに `yield` で値を返す
- `next()` 関数で次を取り出す。
-  `for` で取り出せば例外は発生しない。

```python
def gen(str):
  for c in str.upper():
    yield c

yes = gen("yes")
print(next(yes)) # Y
print(next(yes)) # E
print(next(yes)) # S
print(next(yes)) # StopIteration例外

for h in gen("hello"):
  print(h, end="")

# HELLO
```

### ジェネレータ式

- `(式 for 変数 in イテレート可能なオブジェクト)`
- 一見するとタプルの内包表記に見えるが、タプルの内包表記はない。

```python
gen = (c for c in "hello".upper())

for g in gen:
    print(g, end="")
```

### ファイル読み込み

- オープンとクローズ
    - `f = open(ファイル名, モード, エンコーディング)`
        - デフォルトは、モード＝"r"、エンコーディング="utf_8"
    - `f.close()`
- read
    - `str = f.read()` ファイル全体をまとめて文字列として読み込む
    - `str = f.read(5)` 指定した文字数を分だけ読みこむ。もう一度`read(文字数)`で続きから読みこむ
- readlines
    - `lines = f.readlines()` 各行をリストの要素として読み込む。改行コードは`\n`となる。
    - `lines = f.readlines(2)` サイズを制限して読みこむ 
- leadline
    - `f.readline()` １行ずつ文字列として読みこむ。ファイルの終わりになると、空文字を返す。
    - `for i, line in enumerate(f)` を使用しても、`line`に１行ずつ読みこむ。
- with文を使えば、close不要。


```python
with open("hello.txt") as f:
    print(f.read())

with open("hello.txt") as f:
    for i, line in enumerate(f):
        print(i, line, end="")
```


### クラス

- クラス名は慣習的に、`MyClass`のようなアッパーキャメルケースを用いる
- コンストラクタ `def __init__(self, 引数1, 引数2, ...):`
- インスタンス変数に値を入れる `self.インスタンス変数名 = 値`
- インスタンスの生成 `変数 ＝ クラス名(引数, ...)` コンストラクタの第一引数`self`には、自動的に自分自身が入るので、第二引数以降を指定する。
- コンストラクタで値を代入した変数がインスタンス変数、メソッドの外部で値を代入したものがクラス変数となる
- メソッドの定義は、`def メソッド名(self, 引数, ...):`
- privateメソッドは、メソッド名の前に`__`をつける。 外部からアクセスできるが、アクセスしてほしくないメソッドは`_`をつける
- getter, setterメソッドは慣習的に `get_name` `set_name` のように命名する。
- `プロパティ名 = propery([セッターメソッド[,ゲッターメソッド]])` でプロパティを設定する

```python
class Customer:
    # クラス変数
    bmi = 22

    # コンストラクタ
    def __init__(self, number, name, height=0):
        # インスタンス変数
        self.__number = number
        self.__name = name
        self.__height = height

    # ゲッター
    def get_name(self):
        return self.__name

    def get_number(self):
        return self.__number

    # セッター
    def set_number(self, number):
        self.__number = number

    def get_height(self):
        return self.__height

    # 標準体重を算出する
    def std_weight(self):
        return Customer.bmi * (self.height / 100) ** 2

    # プロパティの設定
    name = property(get_name)
    number = property(get_number, set_number)
    height = property(get_height)


if __name__ == "__main__":
    # オブジェクトの生成
    taro = Customer(101, "斎藤太郎", 180)
    # 値を変更する
    taro.number = 150
    print("No.{} の {} さんの標準体重は {:.2f}kg です。".format(
        taro.number, taro.name, taro.std_weight()))

# No.150 の 斎藤太郎 さんの標準体重は 71.28kg です。
```


### モジュール

- モジュール名は、ファイル名から拡張子`.py`を除いた名前になる。
    - ファイル名が`customer_m1.py`のとき、`customer_m1`がモジュール名となる。
- モジュール名、ファイル名は慣習的に小文字とアンダースコアが推奨される。
- `if __name__ == "__main__":` のブロックは、ファイル名のみが指定されたときに呼ばれる。

### クラスの継承

- `class サブクラス名(スーパークラス名)` で定義する。
- `super().__init__(引数)` でスーパークラスのコンストラクタを呼び出す

参考：[基礎Python 基礎シリーズ](https://www.amazon.co.jp/%E5%9F%BA%E7%A4%8EPython-%E5%9F%BA%E7%A4%8E%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E5%A4%A7%E6%B4%A5-%E7%9C%9F-ebook/dp/B01CZDTIKC)