「オブジェクト指向完全に理解したマン」は誰もが通る道です。オブジェクト指向にすれば、悪夢のようなグローバル変数スパゲティや、どんなメンバを持ってるのかさっぱりわからない継承無間地獄を生み出すことを防ぐことができます。
しかし、新規でコードを作ることになったとき「とりあえずクラス作っとこ」って思ってませんか?
クラスの落とし穴
単なる「グローバル変数もどき」を作ってるだけではないですか?
オブジェクト指向を使えば、確かに関数のスコープをクラスに閉じ込めることができます。「これグローバル変数にしたいけど、グローバル変数はバッドプラクティスだから、クラス作ってメンバ変数にしとこう」って思ってませんか?
Nx=100
# ...
class main:
#クラス変数の場合
self.Nx=100
#インスタンス変数の場合
def __init__(self):
self.Ny=100
#...
if __name__ == "__main__":
myobj=main()
#...
javaのような純粋なオブジェクト指向言語ではこの書き方は正しいのかも知れません。ですがそういうわけでもない言語で**いちいちmainクラスを作成してインスタンス化する意味はあるのでしょうか?**if文以下を書く分コード量が増えてませんか?
コンポジットが最強だと思ってませんか?
オブジェクト指向で書かれたライブラリも非常に多いので、ライブラリのクラスを再利用したくなることも多いと思います。そのとき、一緒に抱えるデータがあるとき、クラスにまとめたくもなるでしょう。
クラスを再利用したいとき、真っ先に思い出すのは継承ですが、むやみな継承はメンバのありかをわからなくするので一般にはバッドプラクティスとされます。
# こんなimportが書いてあると超最悪
from hogelib import *
from fugalib import *
class myclassA(myclassB):
#引数の数をよく覚えてくださいね
def Bmethod(self,arg1,arg2):
#...
# ---------------------------------
# 超長い記述
# ---------------------------------
if __name__ == "__main__":
myobj=myclassA()
myobj.Bmethod(1) #これってどこの関数呼んでるんですか?
これを回避するために使われるのがコンポジットという手法です。新たなクラスのメンバにクラスインタスタンスを持たせることで、関数名のスコープを閉じ込めることができます。OOPのバイブルとして有名なGoF本にも基本原則として「コンポジット使え」って書いてあります。
class myclassA:
def __init__(self):
self.myobj=myclassB()
しかし、そんなコンポジットにもデメリットはあります。myclassAのメソッドとしてBmethodを直接呼び出すことはできないことです。呼び出せるようにするには定義してやる必要があります。
def Bmethod(self,args):
myobj.Bmethod(args)
この例では1つだけだったのでよかったですが、もしmyclassBが大量のメソッドを持っていたとしても全部書き直しますか?
クラスにもオーバーヘッドがかかる
クラスは結構高級な機能です。高級な機能にはオーバーヘッドがかかるものです。パフォーマンスが重要な場面ではそのオーバーヘッドが命取りになることもあります。
個人的な経験ですがクラスを作ると5分かかった処理が、バラして書くと数秒になったことがあります。言語やコンパイラによっては最適化がうまくなされずにえげつなくオーバーヘッドがかかることもあるのです。
果たしてそれはシステムとして再利用されうるのか?
ここまでオブジェクト指向は万能ではないことを書いてきました。それでもオブジェクト指向が使われるのにはきちんとした理由があります。それは再利用がしやすいということです。
コンポジットのところでmyclassAを定義するのは死ぬほど面倒だと書きましたが、逆に一度定義してしまえばmyclassAのデータ構造や処理を再利用できます。一般に再利用可能なコードはそうでないものと比べて工数がかかるものですが、再利用するときいちから書き直すよりはかかりません。
しかし、最初のmainクラスのように一回ポッキリで再利用することもないコードを工数をかけてわざわざクラス化する必要はあるのでしょうか。
まとめ
クラスを使うと抽象的でエレガントなコードが書けるので、中級プログラマはついつい多用してしまいがちです。ですがその裏にはコーディング、パフォーマンスでコストもかかっているのです。OOPを使うことはコストと再利用性のトレードオフなのです。
クラスを作るときは「本当にそのクラスを再利用することがある?」と一度問うてみてから考えましょう。