Python始めて3ヶ月のメモ


初心者の躓きポイントと知っておくと良いテクニックのメモ


## 三項演算子
公式：`(変数) = (条件がTrueのときの値) if (条件) else (条件がFalseのときの値)`

```python
score = 100
result = "good" if score > 80 else "bad"
print(result) # good
```


## else

ループ処理が終わったタイミングもとれるらしい

```python:while
i = 0
while i < 3:
    print(i)
    i += 1
else:
    print("while, end")
```

```python:for
for i in range(3):
    print(i)
else:
    print("for, end")
```


# pass

何もしない。外枠だけざっと決めたいときなどに使う

```python
def say_hello():
    pass
print(say_hello()) # None
```

> 参考
[Pythonのpass文の使い方](http://uxmilk.jp/19515)


## format

`str(1)`といったキャストが複数続いた時に使えるとよりスマート

```python
text = 'name -> {0:>10s}\nscore -> {1:<10.2f}'.format('sato',30.2)
# name -> 表示幅:10, s:string, >:右揃え
# score -> 表示幅:10, 小数点以下2桁, f:float, >:左揃え
print(text)
# name ->       sato
# score -> 30.20     
```

↓こういうのも便利

```python:桁数指定でゼロ埋め
print('{:05}'.format(255)) # 00255
print('{:08}'.format(255)) # 00000255
```


## スコープ

関数内でのグローバル変数の扱い

```python:代入する場合はglobal宣言しないとエラー
x = 5 
def add():
    global x # 宣言しないと書き換えられない
    x += 1
add() 
print(x)
```

```python:参照するだけならglobal宣言は要らないけど・・・
# 参照するだけでもglobal宣言しておいた方がわかりやすい
x = 5 
def print_x():
    print(x)
print_x() 
```

しかし副作用を防ぐため、できる限り関数内からグローバル変数にアクセスしないほうがいい

```python:引数で渡す形が良い
x = 5 
def add(x):
    x += 1
    return x
x = add(x) 
print(x)
```

## リスト

```python:リストの落とし穴
x = ["a", "b", "c"]
y = x.append("d")
print(x) # ['a', 'b', 'c', 'd'] 変数が置き換わる
print(y) # None 返ってくるのはNone
```

```python:文字列の場合
x = "abcdef"
y = x.upper()
print(x) # abcdef 変数はそのまま
print(y) # ABCDEF 返ってくるのは文字列
```

|オブジェクトの種類|メソッドを実行した後の変数|メソッドが返すもの|
|---|---|---|
|文字列|変数はそのまま|文字列|
|リスト|変数が置き換わる|None|

## リスト内包表記

### 条件に一致するものに絞る | if

mapとfilterを同時に処理できているイメージ
if文でTrueとなったものがリスト作成の対象になる

```Python:eを含む名前を取り出し小文字にする
users = ["Yo", "Ken", "Nao", "Shin", "Lee"]
users = [u.lower() for u in users if u.find("e") != -1]
print(users) # ['ken', 'lee']
```

### 複数リストを同時にループ | zip

```Python:「あいうえお・・・」を分解し元に戻す
str_ = list('あいうえおかきくけこさしすせそ')
a = str_[::2] # 最初から最後まで2つ目に出てきたもの=インデックス番号が偶数（０含む）
b = str_[1::2] # 1から最後まで2つ目に出てきたもの=インデックス番号が奇数
print(a) # ['あ', 'う', 'お', 'き', 'け', 'さ', 'す', 'そ']
print(b) # ['い', 'え', 'か', 'く', 'こ', 'し', 'せ']
# 区切り文字列.join(シーケンス）
moto = "".join([ _a + _b for _a,_b in zip(a,b) ])
print(moto) # あいうえおかきくけこさしすせ
```

https://docs.python.jp/3/library/functions.html#zip

## セット / ディクショナリー

set
=> 重複なし、順序なし、ハッシュで捜査

dictionary
=> setにおけるハッシュの使い方にValueを追加したもの

```python
s = {1,2,3,4,5}
print(type(s)) # <class 'set'>

d = {} # 空だとdictionaryになるので注意
print(type(d)) # <class 'dict'>
```

### 集合型(set)の数学的演算

```python
colors1 = {"white","black","red","green"}
colors2 = {"white","black","yellow"}
# 集合の差
print(colors1 - colors2) # {'green', 'red'}
# 集合に含まれるかどうか
print("blue" in colors2) # False
# 集合和
colors3 = colors1 | colors2
print(colors3) # {'white', 'green', 'red', 'black', 'yellow'}
# 共通部分
colors4 = colors1 & colors2
print(colors4) # {'black', 'white'}
```

## 可変長引数とキーワード引数

### タプルと辞書型

|記述|受け取る型|
|---|---|
|*|タプル|
|**|辞書型|

```Python
# 可変長引数、キーワード引数の順番は守る
def print_args_kwargs(*args, **kwargs):
    print(args) # (1, 2, 3)
    print(kwargs) # {'age': 25, 'name': 'sato'}
print_args_kwargs(1,2,3, age=25, name='sato')
```

### キーワード引数の辞書化

```Python:引数をdictionaryで渡す
def say_hello(name, age):
    print(name, age) # sato 25
user = {'name':'sato', 'age':25}
say_hello(**user) # ** 辞書型
```

> 参考
[Python超入門(番外1)：*arg と **kwarg](http://iatlex.com/python/arg_kwargs/)


## クラス

### self

クラスから作られるインスタンスを指す。
クラスのインスタンスメソッドやコンストラクタの第一引数。忘れがち。
selfに紐づく変数は「インスタンス変数」、メソッドは「インスタンスメソッド」と呼ぶ。

### クラス変数（定数）・メソッド

classに紐づく変数は「クラス変数」、メソッドは「クラスメソッド」と呼ぶ。

```python
class Player:
    # クラス変数
    count = 0
    # クラス定数（大文字）
    GUILD = "KoB"
    def __init__(self):
        Player.count += 1
    # クラスメソッド
    @classmethod 
    def show_count(cls):
        # selfを受け取っていないので
        # インスタンス変数・メソッドは使えない
        print("{} instances".format(cls.count))
        
    # スタティックメソッド
    # 第一引数のないクラスメソッドのようなもの
    # インスタンス化せずに呼べる
    @staticmethod
    def show_guild():
        print(Player.GUILD)

player01 = Player()
player02 = Player()
player03 = Player()

# インスタンス化せずに呼べる
print(Player.count) # 3
Player.show_count() # 3 instances

# 同名のインスタンス変数がない場合、インスタンスからもクラス変数を呼べる
print(player01.count) # 3

Player.show_guild() # KoB
```

### クラス定数でデータ管理

↓こんな感じでデータを管理すると便利

```python:定数で色を管理する
class Color:
    MAIN = '#f00'
    SUB = '#00f'
    FONT = '#fff'
print(Color.MAIN) # #f00
```

### プライベート変数・メソッド

アンダースコア2つ「__」で外部からアクセスできなくなる
アンダースコア1つ「_」は形だけ

```python
class Player:
    def __init__(self):
        self.name = 'sato'
    def __method(self):
        print(self.name)

player01 = Player()
player01.__method() # error
```

※プライベートメソッド・変数は「name mangling」されているだけなので、強引に呼び出そうと思えば可能だがやっちゃダメ。

### ゲッター・セッター

外部から操作する必要のあるインスタンス変数に使う

#### getter

```python:公式
class ClassName:
    @property
    def getterName(self):
        return value
```

```python
class Clock:
    def __init__(self, hour):
        self._hour = hour

    @property
    def hour(self):
        return self._hour

clock = Clock(10)
print(clock.hour) # メソッドに変数のようにアクセスできる
clock.hour = 12 # 値の変更はできない AttributeError: can't set attribute
```

#### setter

```python:公式
class ClassName:
    @getterName.setter
    def getterName(self, value):
```

```python
class Clock:
    def __init__(self, hour):
        self._hour = hour

    @property
    def hour(self):
        return self._hour
    
    @hour.setter
    def hour(self, value):
        self._hour = value

clock = Clock(10)
clock.hour # 10
clock.hour = 6 # アクセスできるようになった
clock.hour # 6
```

## ラムダ式

`lambda 引数：式`
関数をオブジェクトとして返す
関数渡しの際にいちいち関数をつくるのではなく、無名関数で済ませられる場合などに使えるとスマート

```python
lambda_test = lambda x, y : print('lambda_test : {}, {}'.format(x, y)) # function <lambda>
lambda_test('hello', 'lambda') # lambda_test : hello, lambda
```

### map

`map(function, iterable)`
第一引数の関数を、第二引数のリスト（タプル）に適応し、結果を返す

```python
map_obj = map(lambda x : x * 2, range(10))
print(list(map_obj)) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
```

### filter

`filter(function, iterable)`
第一引数の関数を、第二引数のリスト（タプル）に適応し、Trueな要素を回収する

```python
filter_obj = filter(lambda x : x % 2 == 0, range(10))
print(list(filter_obj)) # [0, 2, 4, 6, 8]
```


## デコレータ

関数の前後に任意の処理を追加する

```python
import time

def time_log(func):
    def wrapper(*args,**kwargs):
        
        import datetime
        start = datetime.datetime.today()
        print("--- start", func.__name__)
        
        # 関数実行
        func(*args, **kwargs)
        
        end = datetime.datetime.today()
        delta = end - start
        print("--- end", func.__name__, delta, "sec")
    
    return wrapper #関数オブジェクトを返す

# デコレータ名を記述して処理を追加        
@time_log 
def test1():
    print("sleep 1sec")
    time.sleep(1)
    
@time_log
def test2():
    print("sleep 2sec")
    time.sleep(2)
    
test1()
test2()
```

---

> 参考
http://dotinstall.com/lessons/basic_python_v3
http://www.yoheim.net/