Python 基礎

## 目次
1. [基礎文法](#1-基礎文法)
1. [演算子](#2-演算子)
1. [制御文](#3-制御文)
1. [関数](#4-関数)
1. [モジュールとクラス](#5-モジュールとクラス)

## 1. 基礎文法

### 基本的なルール
* 文末のセミコロンは不要(つけることもできる)
* {}で処理をまとめるのではなく、インデントで処理をまとめる
* メンバアクセスはドットで行う
* 処理を複数行にまたぐ場合、改行にはバックスラッシュを使用する

### 変数
* 「変数名 = 値」で宣言できる
* 「変数名:型名 = 値」で型を明示して変数宣言できる

※ただし、実行時に指定型以外の値を入れても、実行時エラーとはならないので注意
型指定はあくまで制作側へのヒント。

```python
# 型指定なし
val = 10 

# 型指定あり
val:str = 'あいうえお'
```

### コメント
* 単一行は「#」
* 複数行のコメント機能はないが、3重のシングルクォートorダブルクォートで囲むことで、複数行の文字列扱いにできる

```python
# 単一行コメント

'''
  コメント1
  コメント2
  コメント3
'''
```

### データ型

|データ型|説明|例|補足|
|---|---|---|---|
|int|整数|1||
|float|浮動小数点|2.5||
|complex|複素数|1 + 1j|数字にjをつけると複素数リテラルになる|
|bool|真偽値|True, False|Trueは1, Falseは0扱い|
|str|文字列|'abc', "def", '''ghi''', """jkl"""|3重のクォートを使うと複数行にまたがる文字列を定義できる|
|list|リスト型|['hoge', 1, True]||
|dict|辞書型|{'key1': 'value1', 'key2': 'value2'}||
|tuple|タプル型|('hoge', 1, True)|要素の変更ができない||
|set|集合型|set(['hoge', 1, True]), set('hogehoge')|リスト型の値か、文字列を受け取り、重複した値を抜いて返す、文字列の場合は１文字ずつバラす|
|None|何もなし|None||

## 2. 演算子

### 算術演算子

|演算子|説明|例|
|---|---|---|
|+|加算|1 + 2 # 3|
|-|減算|1- - 5 # 5|
|*|乗算|10 * 2 # 20|
|**|累乗|2 ** 3 # 8|
|/|除算|10 / 3 # 3.3333333|
|//|切り捨て除算|10 // 3 # 3|
|%|剰余|10 % 3 # 1|

### 比較演算子

|演算子|説明|
|---|---|
|==|等しい|
|!=|等しくない|
|>|より大きい|
|>=|以上|
|<|より小さい|
|<=|以下|
|is|同一オブジェクト|
|is not|異なるオブジェクト|
|in|a in b aがbに含まれる|
|not in|a not in b aがbに含まれない|

### 論理演算子

|演算子|説明|
|---|---|
|and|a and b aとbが共に真の場合に真|
|or|a or b aかbの少なくとも1つが真の場合に真|
|not|not a aが真の時に偽、偽の時に真|

### ビット演算子

|演算子|説明|
|---|---|
|&|論理積|
|｜|論理和|
|^|排他的論理和|
|<<|左シフト|
|>>|右シフト|
|-|ビット反転|

### 三項演算子
* (条件が真の時の値) if (条件) else (条件が偽の時の値) で書く

```python
val = 1
print('OK' if val > 0 else 'NG') # OK
```

### 文字列演算

|演算子|説明|例|
|---|---|---|
|+|文字列の連結|'abc' + 'def' # abcdef|
|*|文字列を繰り返し結合|'ab' * 3 # ababab|
|[n]|n番目の文字を切り出す|'abcdef'[2] # c|
|[n:m]|n~m-1番目の文字を切り出す|'abcdef'[2:4] # cd|
|[n:]|n番目以降の文字を切り出す|'abcdef'[2:] # cdef|
|[:m]|m-1番目までの文字を切り出す|'abcdef'[:5] # abcde|
|[n:m :s]|n~m-1番目の文字をs個飛ばしで切り出す|'abcdef'[2:5:2] # ce|

## 3. 制御文

### 条件分岐
* if...elif...else文(他言語で言うifelse文)
* 他言語で言うswitch文はないが、inを使うことで代用できる
* 範囲指定もできる

```python
x = 10

# if...elif...else文
if x == 5:
  ...
elif x == 10:
  ...
else:
  ...

# 範囲指定
if 1 < x < 10:
  ...

# switch文ライクな書き方
# inを使う
if x == 5:
  ...
elif x in (2,3):
  ...
elif x in (3,4):
  ...
else:
  ...

# Noneの比較には、isやis notを使う
data = None
if data is None:
  ...
```

### 繰り返し文
* pythonのfor文は他言語のforeach文に相当
* while文はあるが、do~while文はない
* rangeを組み合わせることで、他言語のfor文が実現できる

```python
# while文
val = 1
while val < 3:
  print(val)
  val += 1

# for文とrange関数
for i in range(2)
  print(i) # 0, 1

# for文と文字列(リスト, 辞書など)
for c in 'hoge'
  print(c) # h,o,g,e
```

#### continue, break

```python
# continue
# xが3の時continueする
for x in range(5):
  if x == 3:
    continue
  print(x)

# break
# xが3の時breakする
for x in range(5):
  if x == 3:
    break
  print(x)
```

## 4. 関数
* 「def」を使って定義する

```python
# 普通のやつ
def fnc(a, b):
  return a + b 

# デフォルト値
def fnc(a, b=1):
  return a + b

# 可変長引数
# *をつける
def fnc(a, b, *args):
  print(a, b, args)

# キーワード付きの可変長引数
# **をつける
def fnc(a, b, **args):
  print(a, b, args)

# 引数、返り値の型指定
# ただし、処理を動かすとエラーは起きないので注意
def fnc(a:int, b:int) -> int:
  return a + b
```

### 例外処理
* 「try ~ except ~ else ~ finally」で表せる
* 意図的に例外を起こしたい場合は、「raise」を使う

```python
try:
  ...
# 例外発生時の処理
except Exception as e:
  ...
# 例外が発生しなかった場合の処理
else:
  ...
# 例外の有無関係なく、必ず走る処理
finally
  ...
```

### pass文
* 何もしないことを明示する

```python
for i in range(10)
  if(i == 1):
    print(i)
  else:
    pass # 何もしない

def hoge():
  pass
```

## 5. モジュールとクラス

### モジュールのインポート

#### 同階層のインポート

```python
# sub.py(インポートされる側)
def subFnc():
  ...

# インポートする側
# sub.pyをインポートする
import sub # 拡張子は付けない
sub.subFnc()

# sub.pyのsubFncをインポートする
from sub import subFnc
subFnc()
```

#### 他階層に一つだけ存在するファイルのインポート

```python
# sub.py(インポートされる側)
def subFnc():
  ...

# インポートする側
# subdirフォルダのsub.pyをインポートする
from subdir import sub
sub.subFnc()

# 次のような書き方でもOK
import subdir.sub
subidir.sub.subFnc()
```

#### 他階層に複数存在するファイルのインポート

```python
# サブフォルダに複数のファイルがある場合は
# __init__.pyを用意し、パッケージ化する必要がある

# __init.py
from . import sub1
from . import sub2

# sub1.py
def subFnc():
  ...

# sub2.py
def subFnc():
  ...

# main.py(インポートする側)
import subdir
subdir.sub1.subFnc()
subdir.sub2.subFnc()
```

#### 標準ライブラリのインポート

```python
import calendar
print(calendar.month(1999,12)
```

#### 外部ライブラリのインポート
* PyPI(https://pypi.python.org/pypi)というサービスからインストールする方法が一般的

```shell
# インストール
$ pip install [モジュール名]

# アンインストール
$ pip uninstall [モジュール名]

# 詳細確認
$ pip show [モジュール名]

# インストール済みモジュールの確認
pip list

# Macの場合は「pip」を「pip3」に読み替える
```

### クラス

#### 基本的なクラスの宣言
* インスタンスメソッドの第一引数には、必ず自分自身を示すselfを定義する

```python
class Member:
  # クラス変数
  LANG = 'JP'

  # コンストラクタ
  # __init__で宣言できる
  def __init__(self):
    self.name = ''

  # getter
  def getName(self):
    return self.name

  # setter
  def setName(self, name):
    self.name = name

taro = Member()
taro.setName('太郎')
print(taro.getName()) # 太郎
print(Member.LANG) # JP
```

#### クラスの継承
* 「class 子クラス名(親クラス名):」で定義できる

```python
# 親クラス
class Parent:
  def __init__(self, a, b):
    self.a = a
    self.b = b
  def hello(self):
    print("hello"　 + self.a)

# 子クラス

# 親クラスをインポート
from dir1 import Parent

# 親クラスを継承
class Child(Parent):

  # 親クラスのオーバーライド(一部上書き)
  def __init__(self, a, b, c):
    super().__init__(a, b)
    self.c = c 

  # 親クラスのオーバーライド(全て上書き)
  def hello(self):
    print(self.b)

  # 子クラスで新たに定義したメソッド
  def bye(self):
    print("good bye" + self.c)
```

#### クラスメソッド
* インスタンス化しなくても使用できるメソッド
* メソッドの一番上に@classmethodと付けることで定義できる
* 第一引数にはそのクラス自身をclsという名前で指定する(これにより、クラスのメンバにアクセスできる)

```python
class Coordinate:
    """ 座標クラス """
 
    def __init__(self):
        """ 初期化 """
        self.x = 0
        self.y = 0
 
    def show_coordinate(self):
        """ 座標を表示する """
        print(self.x, self.y)
 
    @classmethod
    def create_new_cood(cls, x, y):
        """ Coodinateオブジェクトを生成して返す """
        new_cood = cls() # Coodinateオブジェクトを生成
        new_cood.x = x # 座標を設定
        new_cood.y = y # 座標を設定
        return new_cood
 
cood = Coordinate() # インスタンスを生成する
cood2 = cood.create_new_cood(10, 20)
cood2.show_coordinate()
```

#### スタティックメソッド
* インスタンス化してなくても使用できるメソッド
* メソッドの一番上に@staticmethodと付けることで定義できる
* クラスのメンバにはアクセスできない

```python
import math
 
class Coordinate:
    """ 座標クラス """
  
    def __init__(self):
        """ 初期化 """
        self.x = 0
        self.y = 0
  
    def show_coordinate(self):
        """ 座標を表示する """
        print(self.x, self.y)
 
    @staticmethod
    def calc_dist(cood1, cood2):
        """ 座標間の距離を計算します """
        x = cood1.x - cood2.x
        y = cood1.y - cood2.y
        return math.sqrt((math.pow(x, 2) + math.pow(y, 2)))
 
 
cood1 = Coordinate() # インスタンスを生成する
cood1.x, cood1.y = 100, 100
 
cood2 = Coordinate() # インスタンスを生成する
cood2.x, cood2.y = 200, 200
 
dist = Coordinate.calc_dist(cood1, cood2) # スタティックメソッドを実行
print(dist)
```

### クロージャ
* 関数のローカル変数を参照するような関数

```python
def counter():
  count = 0

  # クロージャ
  # nonlocalをつけると、一つ外側のスコープに属する変数への代入が可能になる
  def inner_counter():
    nonlocal count
    count += 1
    return count

  return inner_count

cnt = counter()
print(cnt()) # 1
print(cnt()) # 2
print(cnt()) # 3
```