Pythonのコードをきれいに書くコツ

[10 Python Tips and Tricks For Writing Better Code](https://www.youtube.com/watch?v=C-gEQdGVXbk)の内容を軽く日本語でまとめました。
英語のヒアリング未熟なので、もしかしたら間違っている所があるかもしれません。

## 1) Ternary Conditionals：条件式
ternary operatorsとも呼ぶらしい。
```python
condition = True

if condition:
    x = 1
else:
    x = 0

print(x)
```
Trueなら1を、Falseなら0を返すコードです。
このコードの```if```文を1行で書くと、
```python
x = 1 if condition else 0
```
このように、コードをシンプルかつ分かりやすく書ける方法がないか考えることが大事です。

## 2) Underscore Placeholders：アンダースコアで強調させる
大きい数字が出てきたら、アンダースコア(```_```)で強調すると分かりやすくなります。

```python
num1 = 10000000000  # 分かりにくい

num2 = 10_000_000_000  # 分かりやすい

print(f'{num2:,}')
#　10,000,000,000
```

桁数3つごとで区切って数字を分かりやすくできる。
また、printで出力する時に工夫すれば、より分かりやすくなる。

## 3) Context Managers:コンテキストマネージャ
コンテキストマネージャとは、
with文の実行時に、*runtime context* を定義するオブジェクトのことです。

＊*runtime context* とは
```__enter__()```呼び出しで組み立てられて、```__exit__()```呼び出しで取り壊される環境のこと。

コンテキストマネージャは必ず、特殊メソッドの```__enter__()```と```__exit__()```を定義しないといけないらしい。

実装例 👇
```python
f = open('test.txt','r')

file_contents = f.read()

f.close()

words = file_contents.split(' ')
word_count = len(words)
print(word_count)
```
上のコードの最初の3行について、with文でコンテキストマネージャを呼び出すと、
```python
with open('test.txt','r') as f:
    file_contents = f.read()
```
かなり短くなる。
- 少ないコードで可読性増す (特に例外処理の部分で高い効果を発揮する)
- 前処理（```__enter__```）と、後処理（```__exit__```）を強制する

といったメリットがあります。

## 4) Enumerate : enumerate関数

```python
names = ['Mirai','Tech','Denshi']

index = 0
for name in names:
    print(index,name)
    index += 1
```
よく見かけるこのようなコード。
```enumerate```関数を使えば、```for```文がとてもシンプルになります。
```python
for index, name in enumerate(names,start=1):
    print(index, name)
```

## 5) Zip : zip関数
[ヒーロー]と、[ヒーローの名前]をリストにして表示させたいとします。
先程の```enumerate```関数を使って書いてみます。
```python
names = ['Peter Parker','Clark Kent','Bruce Wayne']
heros = ['Spiderman','Superman','Batman']

for index, name in enumerate(names):
    hero = heros[index]
    print(f'{name} is actually {hero}')
```
実は、for文の中身で、```zip```文を使えば、もっと短く書けます。
```python
for name, hero in zip (names, heros):
    print(f'{name} is actually {helo}')
```
この```zip```関数はリストが増えるほど、その効果を発揮します。
例えば、先程のリストに、[ヒーローが活躍する世界]を追加する場合は、
```python
names = ['Peter Parker','Clark Kent','Bruce Wayne']
heros = ['Spiderman','Superman','Batman']
universes = ['Marvel','DC','DC']

for name, hero, universe in zip (names, heros, universes):
    print(f'{name} is actually {helo} from {universe}')
```
このように、```zip```関数はリストなどを簡単にまとめられます。
名前はzipファイルから来ているのでしょうか？

## 6) Unpacking : アンパック
アンパックとは、タプルやリストの要素を展開して複数の変数に代入することです。
様々な要素の取り出し方ができるので便利です。

### アンパックの基本
```python
# Normal
items = (1,2)
print(items)
# (1,2)

# unpaccking
a, b = (1, 2)
print(a)
print(b)
# 1
# 2

# Error!
a, b, c = (1, 2, 3, 4)
print(a)
# ValueError:too many values to unpack
```

変数の数と要素の数は一致する必要があります。

### アンダースコア(```_```)を使ったアンパック
pythonでは、必要ない値を、```_``` に代入します。

```python
a, _ = (1,2)
print(a)
print(_)
# 1
# 2
```

### ```*```を使ったアンパック
*を使えば、要素をリストとしてまとめてくれます。
```python
x = (0, 1, 2, 3, 4)
a, b, *c = x
print(a)
print(b)
print(c)
# 0
# 1
# [2, 3, 4]

a, b*, c = x
print(a)
print(b)
print(c)
# 0
# [1, 2, 3]
# 4
```
[こちら](https://note.nkmk.me/python-tuple-list-unpack/)でもっと詳しく解説しています。

## 7) Setattr/Getattr : 属性の操作を分かりやすく
この関数を使えば、明示的に属性を操作でき、どんな風に設定したか分かりやすくなります。

それぞれ、「Set attribute」 「Get attribute」 の略でしょうか？
```python
class Person():
    pass

person = Person()

first_key = 'first'
first_val = 'Bun'

# setattrを使わない場合
person.first_key = first_val
print(person.first)

# setattrを使う場合
setattr(person, first_key, first_val)
#setattr(オブジェクト,属性名,属性値)
first = getattr(person, first_key)
print(first)
# Bun
```
上記コードの```setattr```では、```person```オブジェクトの属性```first_key```(ここではfirst)に値```first_val```(ここではBun)を設定しています。
そして、```getattr```で、オブジェクトと属性を取得しています。

ややこしいことをしているように思いますが、どんな操作をしたのか分かりやすく、属性が増えれば増えるほど効果を発揮します。

属性が増えた時は、辞書を絡めると分かりやすくなります。

```python
class Person():
    pass

person = Person()

person_info = {'first':'Bun', 'last':'Tarou'}

for key, value in person_info.items():
    setattr(person, key, value)

for key in person_info.keys():
    print(getattr(person, key))

# Bun
# Tarou
```

## 8) GetPass : パスワード保護
```getpass```を使えば、入力したパスワードを隠すことができます。
ユーザーに名前とパスワードを入力させたいとします。
```python
username = input('Yourname: ')
password = getpass('Password: ')

print('Logging in...')
```

このままだと、入力する時にパスワードが丸見えになり、横からチラ見されたらやばいです。
これを防ぐために、👇のようにします。
```python
from getpass import getpass

username = input('Yourname: ')
password = getpass('Password: ')
repassword = getPass('Again: ')

print('Logging in...')
```