読者です 読者をやめる 読者になる 読者になる

やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Pythonではpartialなclassを定義できない?

ワークフロー

前回の続き。C#partialclassをPythonでできないか調べた。できないっぽい。

partial class

C#なら以下のように同一クラスの実装内容を別ファイルに定義できる。

  • root/
    • package1/
      • Class1_0.cs
        • namespace Package1 { partial Class1 { public int a; } }
      • Class1_1.cs
        • namespace Package1 { partial Class1 { public int b; } }
var c1 = new Package1.Class1()
int val = c1.a + c1.b

partial定義できるメリット

実装をファイルに小分けすると、修正した部分の特定が容易になる。Gitなどのリビジョン管理では変更履歴がわかりやすくなる。

たとえば、1ファイル数千行もあったら見るだけで苦痛。pep8が謳う可読性重要とはなんだったのか。1ファイル1クラス最大300行程度がいい。どうしても1クラスの行数が増えるときはpartialしたい。

Pythonではできない?

PythonにはC#partialclassにあたる概念がなさそう。代わりに以下の方法で似たようなことはできる。

方法 説明
クラス継承 別定義したクラスをimportし、継承する
メソッド代入 別定義したクラスBをimportし、クラスAの変数に別クラスBのインスタンスかそのメソッドを代入する

コレジャナイ。どちらも本質的に違うものである。本当に継承として使いたいものと区別がつかないので使いたくない。代入はそれ自体が面倒だし、処理内容の本質でないコードのため、使いたくない。

しかしPythonの仕組み上、partialclassはできない。 「ファイル=モジュール」という扱いになってしまうせいである。

パッケージ>モジュール>クラス

「ファイル=モジュール」であるため、別ファイルにした時点で別モジュールになってしまう。クラスは何かのモジュール配下に含まれるものだから、同一モジュール(ファイル)に定義するしかない。つまり1クラスを他の複数ファイルに分けて定義することはできない。

以下のクラスはすべて別クラスになる。

  • root/
    • package1/
      • module1.py
        • class Class1:
    • package2/
      • module1.py
        • class Class1:
    • package3/
      • module1.py
        • class Class1:
        • class Class2:
        • class Class3:
from package1 import module1
p1m1c1 = module1.Class1()
from package2 import module1
p2m1c1 = module1.Class1()
from package3 import module1
p3m1c1 = module1.Class1()
p3m1c2 = module1.Class2()
p3m1c3 = module1.Class3()

ファイル=モジュール

ファイルをモジュールとするせいで呼出が冗長になる。

C#Javaでは1ファイル1クラスで定義する。ファイル名はクラス名にする。それをPythonでやると以下のようになる。

  • root/
    • package1/
      • Class1.py
        • class Class1:

すると呼出が冗長に見える。

from package1 import Class1
p1c1 = Class1.Class1()

Class1.Class1()のところがダサい。package1.Class1()もしくはClass1()にしたい。しかしクラスは必ずモジュール(ファイル)の下に配属するものだから省略できない。と思う。

datetimeも同様

これはPythonの標準クラスdatetimeを使ったときに感じていた。

import datetime
print(datetime.datetime.now())
from datetime import datetime
print(datetime.now())

何回datetime書けば気が済むんだよ!と思ってしまう。 コードをたくさん書いていくと、思った以上のストレスになる。

所感

結局Pythonでは、変数などを共有できる同一クラス内で、膨大なメソッドを、複数ファイル小分けにして定義することはできないということか。

以下のどれかしかない。

  • 全部1ファイル内に書く
  • 継承や代入でごまかす
  • 重複コードを書く

Python的には1ファイル内に書くのが良いのだろうけど、どれも嫌だ…。

もしくは、オブジェクト指向デザインパターンをしっかり学べば、うまいこと設計できるのかもしれない。

もしくは、API仕様をDatabase化してリクエストを生成することで重複コードを避けられないか。次回、考えてみる。