【Python】脱初心者のための変数名の付け方

本記事は2024年5月19日に開催された「【オンライン】飛騨高山Pythonの会 #52」での発表内容をまとめたものになります。ご参加いただいた皆様ありがとうございました。月1回の頻度で開催しておりますので、今回ご参加いただけなかった方のご参加をお待ちしております!

📖 参照: 日経ソフトウェア2022年3月号

💡 変数について考える順番

  1. 「変数を使わずに書けないか」を考える
  2. 「変数の有効範囲を狭くして、簡単な変数名にできないか」を考える
  3. 最後に、「良い名前」を考える

サンプルコード

ユーザーの名前リストと年収リスト(※1)から、指定の年収以上(※2)の名前一覧とその上位 X 位以上(※3)の年収の合計値を出力する関数を作成する
※1: 別々のリストだが、同じインデックスに同じユーザーの情報が入っている
※2: 1,000 円単位で指定できるようにする。指定がない場合は 1,000 万円以上
※3: X も指定できるようにする。指定がない場合は上位 2 位まで

リファクタリング前のコード

def show_target_income(name_data, income_data, target=10000, top=2):
    tmp_name_data = []
    tmp_income_data = []
    for income_idx in range(len(income_data)):
        tmp_income = income_data[income_idx]
        if tmp_income >= target:
            tmp_income_data.append(income_data[income_idx])
            tmp_name = name_data[income_idx]
            tmp_name_data.append(tmp_name)

    tmp_income_data2 = sorted(tmp_income_data, reverse=True)
    top_income_data = []
    for income_idx in range(len(tmp_income_data2)):
        if income_idx < top:
            tmp_income = tmp_income_data2[income_idx]
            top_income_data.append(tmp_income)
    total_income = sum(top_income_data)

    print(tmp_name_data)
    print(total_income)

name_data = ['A', 'B', 'C', 'D']
income_data = [100000, 100000, 80000, 3600]
show_target_income(name_data, income_data)

実行結果

['A', 'B', 'C']
200000

1. 「変数を使わずに書けないか」を考える

変数名を考えるのって大変・・・

例えば以下のようなケース

  1. 「売れてるおすすめ商品」の変数名に「recommend_item」と命名
  2. 時間が経って「あなたの行動からのおすすめ商品」が登場し、変数名に「recommended_item_by_actions」と命名

コンテキストを何も知らない人がコードを見たら、「「recommend_item」って何をもとにしたおすすめ?」となってしまう 🤔

このような問題は実際にもよく起きるが、将来のことを完璧に予測することは難しく、良い名前を付けるのは思いのほか大変・・・なので↓

💡 なるべく変数を減らして、良い名前を付けるための作業の負担を減らす

変数を減らすためのテクニック

  • ライブラリや言語の機能を活用する
  • メソッドチェーン方式

「変数を使わずに書けないか」を考えてリファクタリングしたコードがこちら

def show_target_income(name_data, income_data, target=10000, top=2):
    tmp_name_data = []
    tmp_income_data = []
    # 組み込み関数のzip関数を使って書き換え
    for tmp_name, tmp_income in zip(name_data, income_data):
        if tmp_income >= target:
            tmp_income_data.append(tmp_income)
            tmp_name_data.append(tmp_name)

    # Pythonのスライス機能とメソッドチェーンを使って書き換え
    total_income = sum(sorted(tmp_income_data, reverse=True)[:top])

    print(tmp_name_data)
    print(total_income)

name_data = ['A', 'B', 'C', 'D']
income_data = [100000, 100000, 80000, 3600]
show_target_income(name_data, income_data)

スライスとメソッドチェーンを使うことで、年収合計(total_income)を計算していたコードが1行になり、変数を大幅に削減することができました。

また、名前と年収の上位X位を取得するロジックではzip関数を使うことで、変数「income_idx」を削除しています。

2. 「変数の有効範囲を狭くして、簡単な変数名にできないか」を考える

そもそもなぜ「良い名前」を付ける必要があるのか?
 →その変数が重要な意味を持ち、プログラム内で再利用されるため

💡 有効範囲(スコープ)が狭い(=プログラム全体で管理する必要がない)変数は簡単な名前でOK

「変数の有効範囲を狭くして、簡単な変数名にできないか」を考えてリファクタリングしたコードがこちら

def show_target_income(name_data, income_data, target=10000, top=2):
    # リスト内包表記を使って書き換え
    name_and_income_tuples = [(name, income) for name, income in zip(name_data, income_data) if income >= target]
    tmp_name_data = [t[0] for t in name_and_income_tuples]
    tmp_income_data = [t[1] for t in name_and_income_tuples]

    total_income = sum(sorted(tmp_income_data, reverse=True)[:top])

    print(tmp_name_data)
    print(total_income)

name_data = ['A', 'B', 'C', 'D']
income_data = [100000, 100000, 80000, 3600]
show_target_income(name_data, income_data)

ここではリスト内包表記を使うことで、内包表記内でしか使用しない変数名を簡単な名前に変更しています。ロジック自体もシンプルになりました。

コラム:変数名に「_」(アンダースコア)を使う

  • 名前を付けることに全く意味がない変数
  • 捨てる値を受け取る変数
# 例1
for _ in range(3):
    print("hello")

# 例2
value, _ = foo()

3. 最後に、「良い名前」を考える

いよいよ残った変数名に対して「良い名前」を考えていきます。ポイントは、

💡 必要な情報をしっかり変数名にいれておく

ちなみに、

  • リストの場合は複数形の変数名を使うことが多い(例:name_list → names)
  • 辞書の場合は「値_by_キー」形式の変数名を使うことが多い(例:income_by_name)

「良い名前」を考えてリファクタリングしたコードがこちら↓

# 3. 最後に、「良い名前」を考える
def show_target_income(names, incomes, income_threshold=10000, top_income_count_for_sum=2):
    selected_name_and_income_tuples = [(name, income) for name, income in zip(names, incomes) if income >= income_threshold]
    selected_names = [t[0] for t in selected_name_and_income_tuples]
    selected_incomes = [t[1] for t in selected_name_and_income_tuples]

    top_total_income = sum(sorted(selected_incomes, reverse=True)[:top_income_count_for_sum])

    print(selected_names)
    print(top_total_income)

name_data = ['A', 'B', 'C', 'D']
income_data = [100000, 100000, 80000, 3600]
show_target_income(name_data, income_data)

それぞれの変数の内容、役割がより明確になりました。

まとめ

💡 変数について考える順番

  1. 「変数を使わずに書けないか」を考える
  2. 「変数の有効範囲を狭くして、簡単な変数名にできないか」を考える
  3. 最後に、「良い名前」を考える