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


10 Python Tips and Tricks For Writing Better Codeの内容を軽く日本語でまとめました。
ヒアリング未熟なので、もしかしたら間違っている所があるかもしれません。

1) Ternary Conditionals:条件式

ternary operatorsとも呼ぶらしい。

condition = True

if condition:
    x = 1
else:
    x = 0

print(x)

Trueなら1を、Falseなら0を返すコードです。
このコードのif文を1行で書いちゃいましょう。

x = 1 if condition else 0

このように、コードをシンプルかつ分かりやすく書ける方法がないか考えましょう。

2) Underscore Placeholders:アンダースコアで強調させる

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

num1 = 10000000000  #分かりにくい

num1 = 10_000_000_000  #分かりやすい

print(f'{num1:,}')
#出力結果 10,000,000,000

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

3) Context Managers:コンテキストマネージャ

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

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

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

実装例は⇣

f = open('test.txt','r')

file_contents = f.read()

f.close()

words = file_contents.split(' ')
word_count = len(words)
print(word_count)

上のコードの最初の3行について、with文でコンテキストマネージャを呼び出すと、、、

with open('test.txt','r') as f:
    file_contents = f.read()

かなり短くなる。
・少ないコードで可読性増す(特に例外処理の部分で高い効果を発揮する)
・前処理(__enter__)と後処理(__exit__)を強制する
といったメリットがあります。

4) Enumerate:enumerate関数

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

index = 0
for name in names:
    print(index,name)
    index += 1

よく見かけるこんなコード。
enumerate関数を使えば、for文がとてもシンプルになります。

for index, name in enumerate(names,start=1):
    print(index, name)

5) Zip:zip関数

ヒーローと名前をリストにして表示させたいとします。
先程のenumerate関数を使いましょう。

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文を使えば、もっと短く書けます。

for name, hero in zip (names, heros):
    print(f'{name} is actually {helo}')

このzip関数はリストが増えるほど、その効果を発揮します。
例えば、先程のリストにヒーローが活躍する世界を追加したいとします。
この場合、次のように書けます。

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:アンパック

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

アンパックの基本

#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では、必要ない値を_に代入します。

a, _ = (1,2)

print(a)
print(_)

#出力結果
1
2

*を使ったアンパック

*を使えば、要素をリストとしてまとめてくれます。

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

こちらのサイトでもっと詳しく解説しています。

7) Setattr/Getattr : 属性の操作を分かりやすく

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

それぞれ、Set・Get attribute の略でしょうか?

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で、オブジェクトと属性を取得しています。

「なんかややこしいことしてねぇ!?」と思いますが、どんな操作をしたのか分かりやすいですし、属性が増えれば増えるほど、効果を発揮します。

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

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を使えば、入力したパスワードを隠すことができます。
ユーザーに名前とパスワードを入力させたいとしましょう。

username = input('Yourname: ')
password = getpass('Password: ')

print('Logging in...')

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

from getpass import getpass

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

print('Logging in...')