2017-01-09 9 views
1

科学的なPythonパッケージをビルドしようとする中で、わかりやすくするために、主要な機能を別々の.pyファイルに分けることを目指しています。具体的には、あるモデルの複雑な数値計算を1つのpythonファイル(たとえば "processing.py")に分割し、別のpythonファイル( "plotting.py")に可視化するためのルーチンをプロットすることは論理的です。クラスは異なるファイルからメソッド(またはサブクラス)を継承できますか?これは "Pythonic"ですか?

モデルクラスは、すべてのプロット方法を継承し、ユーザーが簡単にアクセスできるようにする必要がありますが、科学的数値コードを視覚化コードから分離することにより、 。

これを達成するための私のビジョンを説明しますが、より良いOOPスタイルが利用可能な場合、これをPythonで実装する方法には苦労しています。 plotting.py、例えば

class ItemPlotter(object): 

    def visualisation_routine1(self): 
     plt.plot(self.values) # where values are to be acquired from the class in processing.py somehow 

とprocessing.pyで:

次のコマンドラインの使用をもたらす
class Item(object): 

    def __init__(self, flag): 
     if flag is True: 
      self.values = (1, 2, 3) 
     else: 
      self.values = (10, 5, 0) 

     from plotting.py import ItemPlotter 
     self.plots = ItemPlotter() 

from processing.py import Item 
my_item = Item(flag=True) 
# Plot results 
my_item.plots.visualisation_routine1() 

マイ実コードはこれよりも複雑になり、Itemは大きなデータセットの属性を持つ可能性があります私はメモリ効率のためにこれらをコピーしないようにする必要があります。

私のビジョンは可能ですか、Pythonのアプローチでさえどうですか? コメントがありません。 OOPやこれを達成するための効率的な方法が評価されます。

PS、私はPy2.7とPy3の互換性を目指しています。ジョンが指摘するように

+5

これは継承もサブクラス化もされていません。それは*作成*です。もちろん、他の場所からのクラスのインスタンスを属性として使用することもできますが、インポートはファイルの先頭に置く必要があります。 – jonrsharpe

+0

実例を教えてください。これを試してみると、私はAttributeErrorを取得します。 'ItemPlotter'オブジェクトには属性 'vales'がありません。ご協力いただきありがとうございます。 – IanRoberts

+1

まあ...はい、そうです、そうではありません。もう、**あなたはサブクラス化していないから**。あなたは 'Item'のインスタンスの中に' ItemPlotter' **のインスタンスを持っていますが、それらは同じオブジェクトではありません( 'self'を共有しません)。おそらく、 'Item' *は' ItemPlotter'から継承しなければならないか、あるいはその逆です。 – jonrsharpe

答えて

1

For convenient and memory-efficient usage, the model class should be able to inherit all the plotting methods, making them easily accessible for the user, yet keeping the code easy to maintain and read by separating scientific numerical code from visualisation code.

、あなたが実際に(とにかくそれを行うためのgenerally preferred方法です)は、組成物ではなく、継承を記述しています。

「アイテムプロッタ」のインターフェイスを定義する抽象クラスを作成し、Itemのインスタンスへのinject it as a dependencyを作成する方法があります。 Itemのクライアントは、のプロットをに委譲する方法を公開することにより、Itemインスタンスによってカプセル化されたデータを簡単にプロットできるようにすることができます。

このアプローチでは、各クラスがSingle Responsibility Principleを尊重し、コードを理解し、維持し、テストするのを容易にします。必要に応じて、別のPythonモジュールでItemItemPlotterを定義することができます。

from abc import abstractmethod, ABC 


class AbstractItemPlotter(ABC): 
    @abstractmethod 
    def plot(self, values): 
     return 


class ItemPlotter(AbstractItemPlotter): 
    def plot(self, values): 
     # plt.plot(values) 
     print('Plotting {}'.format(values)) 
     pass 


class Item(object): 
    def __init__(self, flag: bool, plotter: AbstractItemPlotter): 
     self._plotter = plotter 
     if flag: 
      self.values = (1, 2, 3) 
     else: 
      self.values = (10, 5, 0) 

    def visualisation_routine1(self): 
     self._plotter.plot(self.values) 

if __name__ == '__main__': 
    item = Item(flag=True, plotter=ItemPlotter()) 
    item.visualisation_routine1() 

出力

Plotting (1, 2, 3) 

編集

このコードはPythonの3.5.2を使用して試験しました。私はそれがそのままPython 2.7で動作するかどうかは確かではありません。

+0

これと良いOOPスタイルへのリンクありがとう。これは素晴らしく見えます。私はなぜAbstractItemPlotterクラスを作成する必要があるのだろうか? - これを動作させるには、 "AbstractMethod"としてAbstractItemPlotterのItemPlotterのすべてのメソッドを複製する必要がありますか?さらに、前回の投稿コメントの@Daniel Rosemanのアイデアとこれがどのように比肩していると思いますか? self.plotter = ItemPlotter(self)でプロッタクラスを初期化し、ItemPlotter initでselfへの参照を保存することをシミュレートしますか?ありがとう – IanRoberts

+0

@IanRoberts "これを動作させるには、" AbstractMethod "としてAbstractItemPlotterのItemPlotterのすべてのメソッドを複製する必要がありますか?実装間で変化する可能性が高いメソッドのみ。共通メソッドは基本クラスで実装できます。また、[this post](http://stackoverflow.com/questions/1686174/when-should-one-use-interfaces)を参照してください。 2番目の質問については、ダニエルのアプローチは、実際に 'Item'の中に' ItemPlotter'を格納することを意味するのかどうかわかりませんが、それを行うためのまともな方法のようです。それはクラスをもっと緊密につなぎます。これは一般的に悪いことです。 – Tagc

関連する問題