LoginSignup
20
13
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

Python業務歴1年目から5年目でコードはこう変わった

Last updated at Posted at 2024-07-02

Before

class DBClient:
    PATH = 'hoge/fuga'

    @classmethod
    def insert(cls, recs):
        for rec in recs:
            # ここでは仮でprintするだけとする
            print(f"PATH: {cls.PATH}, name: {rec['name']}, age: {rec['age']}")


records = [
    {"name": "Taro", "age": 20},
    {"name": "Jiro", "age": 18},
    {"name": "Saburo", "age": 12}
]

DBClient.insert(records)

After

import dataclasses
from typing import Final


@dataclasses.dataclass
class Record:
    name: str
    age: int


class DBClient:
    PATH: Final[str] = "hoge/fuga"

    # DBにレコードを挿入する
    def insert(self, records: list[Record]) -> None:
        for record in records:
            # ここでは仮でprintするだけとする
            print(f"PATH: {self.PATH}, name: {record.name}, age: {str(record.age)}")


raw_records = [
    {"name": "Taro", "age": 20},
    {"name": "Jiro", "age": 18},
    {"name": "Saburo", "age": 12},
]
# レコードをインスタンスの配列に変換
records = [Record(record["name"], record["age"]) for record in raw_records]

dbClient = DBClient()
# DBにレコードを挿入
dbClient.insert(records)

解説

ポイント1. dictを乱用しない(今回一番伝えたいこと!)

  • 「辞書(dict)型」の変数を関数の引数にしたり、長い行数(100行とか)の間ずっと使っていたりすると、「このdictって何が入っているんだっけ?」となり、可読性が下がったり、バグの原因になったりします
    • 上記の例のBeforeのinsert関数では本来、rec対しnameageがあるかのキー存在チェックが必要となります
  • そこで、専用のクラスを用意して、辞書型の変数をインスタンスに変換することを強くお勧めします
    • 上記の例ではAfterのRecordクラス
  • そうすることで、「何の項目があるか」「各項目の型は何か」を明示することができます
  • その際、Pythonに元々備わっている 「dataclass」を使うと、__init__関数を省略できるためオススメです
  • dictは非常に便利ですが、自由過ぎるが故、中身が不透明になりやすいので、注意して使ってください

ポイント2. 型定義を書く

  • Pythonは型定義を書かなくても動く言語ですが、メリットが多いので書くことを推奨します
    • 特に関数の引数に対して
  • 可読性の向上に加え、(自分はVSCodeを使っていますが、)エディターでの補完が強力になりますので、ぜひ実感してみてください
    • 上記のポイント1とも相性バツグンです
  • ちなみに、path: str = 'hoge/fuga'といった、型定義と初期値の設定を同時に行う書き方もできます
    • records: list[Record] = []のように初期値が空配列のときによく使います

ポイント3. クォートを統一する

  • ダブルクォートとシングルクォートのどちらを主に使うか、プロジェクトで統一するといいでしょう
    • 私のプロジェクトではダブルクォートを主に使うようにして、「f-string」の中など必要な部分だけシングルクォートを使うようにしていますが、プロジェクトで統一できればどちらでもいいと思います

ポイント4. 安易にclassmethodを使わない

  • @classmethod@staticmethodはきちんと用途を調べ、適切な箇所で使いましょう
  • 少なくとも、過去の私のように「インスタンスを生成しなくていいから行数が一行減るやん!」といった理由で使わないようにしましょう

ポイント5. 無闇に略称を使わない

  • recだとrecordなのかreccomendなのかrecipeなのかわかりません
  • 略さなくても支障がない場合は略さない方がいいと思います
  • ただし、ユビキタス言語などで略称がプロジェクト全体で定義・浸透していれば使っても問題ありません

ポイント6. コメントをきちんと書く

ポイント7. 配列の最後にカンマを置く

あとがき

  • Pythonについて学んだことはまだまだ色々ありますが、要点を絞ってコンパクトにまとめることができたのではと思います
  • BeforeとAfterを書いてみて、コード量がかなり増えていることに自分で驚きました。コードが短ければ可読性が高いってわけではないですね(当たり前か)
  • 本記事とはあまり関係ないかもですが、オブジェクト指向について、「現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法」という書籍が実践的でわかりやすく、ためになったので、宣伝(ダイマ)させていただきます
20
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
13