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
対しname
とage
があるかのキー存在チェックが必要となります
- 上記の例のBeforeの
-
そこで、専用のクラスを用意して、辞書型の変数をインスタンスに変換することを強くお勧めします
- 上記の例ではAfterの
Record
クラス
- 上記の例ではAfterの
- そうすることで、「何の項目があるか」「各項目の型は何か」を明示することができます
- その際、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. コメントをきちんと書く
- コメントは少なすぎるよりは多すぎる方がいいと私は考えています
- 例では使っていませんが、「docstring」を使うとより良いでしょう
ポイント7. 配列の最後にカンマを置く
- 配列などを複数行で記述している場合、最後の要素の後にカンマを置くと、要素を追加したときgitの変更点が見やすくなる、などのメリットがあります
- 上記の例だと
{"name": "Saburo", "age": 12}
の後ですね
- 上記の例だと
- Python公式ドキュメントでも触れられています
あとがき
- Pythonについて学んだことはまだまだ色々ありますが、要点を絞ってコンパクトにまとめることができたのではと思います
- BeforeとAfterを書いてみて、コード量がかなり増えていることに自分で驚きました。コードが短ければ可読性が高いってわけではないですね(当たり前か)
- 本記事とはあまり関係ないかもですが、オブジェクト指向について、「現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法」という書籍が実践的でわかりやすく、ためになったので、宣伝(ダイマ)させていただきます