2017-12-26 14 views
1

私はPythonで書いているプロジェクトの行列を使っています。私は行列を操作するためのライブラリがすでにたくさんあることを知っていますが、私は自分で作成していますので、何が起こっているのか正確に分かっています。親クラスの初期化から条件のサブクラスを初期化する

私はMatrix基底クラスとVectorサブクラスを持っています。どちらも期待どおり個別に動作しますが、はVectorになるようにしたいと考えています(単一の行または列で初期化されている場合)。

Matrixを正しいサイズに初期化すると、self = Vector(...)のようなものを試しました。しかし、それはオブジェクトに影響を与えるようには見えません。私はまたVectorクラスの__init__()メソッドを呼び出すことを考えましたが、私が最も重要にしたいのはVectorのメソッドなので十分ではありません。

このような状況に対処する方法はありますか?

+0

'__init__で魔法をしようとするのではなく、あなたの基準に基づいてクラスを決定するファクトリを使用してください。 –

答えて

2

これは実行するのが最善の方法ではないかもしれませんが、これを行うことができます。結局のところ、Matrixクラスがインスタンス化されている場合、結果はMatrixインスタンスになると予想されます。

ことを達成する一つの方法は、Matrixクラスのコンストラクタをカスタマイズすることです:

class Matrix: 
    def __new__(cls, nrows, ncols): 
     if nrows == 1: 
      inst = super(Matrix, cls).__new__(Vector) 
     else: 
      inst = super(Matrix, cls).__new__(cls) 
     inst.nrows = nrows 
     inst.ncols = ncols 
     return inst 

    def __repr__(self): 
     return '{}(nrows={}, ncols={})'.format(
      self.__class__.__name__, self.nrows, self.ncols) 

デモ:__init__()が使用されている間、インスタンスは実際に、__new__()メソッド内で作成され

>>> m1 = Matrix(2, 5)                                                                                 
Matrix(nrows=2, ncols=5)                                                                               
>>> Matrix(1, 5)                                                                                 
Vector(nrows=1, ncols=5) 

マインド新しく作成されたインスタンスを初期化します。また

@Blckknghtにより以下のコメントで述べたように、Matrixクラスを通じてVectorインスタンスを作成することは、(それが手動で呼び出されなければならないだろう)と呼ばれるばかりではないVector__init__()方法のように、不要な驚きにつながることができます。

class Matrix: 
    def __init__(self, nrows, ncols): 
     self.nrows = nrows 
     self.ncols = ncols 

    def __repr__(self): 
     return '{}(nrows={}, ncols={})'.format(
      self.__class__.__name__, self.nrows, self.ncols) 

class Vector(Matrix): 
    pass 

def make_matrix(nrows, ncols): 
    if nrows == 1: 
     return Vector(nrows, ncols) 
    return Matrix(nrows, ncols) 

デモ:もちろん

>>> make_matrix(1, 5) 
Vector(nrows=1, ncols=5) 
>>> make_matrix(2, 5) 
Matrix(nrows=2, ncols=5) 

ユースケースによっては、しかし、このようにきれいなものを維持し、単にインスタンスの作成のために工場を使用する方がよいかもしれませんmake_matrix()は、Matrixクラスの(クラス/静的)メソッドとして実装することもできますが、それは親クラスをその子クラスの1つと密接に結合させるでしょう...

+0

この状況で' __new__'を使用する際の警告:クラスの '__init__'メソッドは、インスタンスは、それ自身のクラスへの呼び出しによって作成されます。 'Matrix .__ new__'から' Vector .__ new__'を呼び出すことによって 'Vector'のインスタンスを作成すると' __init__'メソッドは呼び出されません。一方、 'Vector'を直接呼び出しようとすると、' Vector'が 'Matrix .__ new__'を継承するので、無限に再帰します。 – Blckknght

+0

これは有効な発言であり、それを推奨しない別の理由で、私はむしろ工場に行くでしょう。これに言及してくれてありがとう。 – plamut

+0

ありがとう!私はこの '__new__'メソッドを見たことがありませんでした。両方の方法を試してみて、どの方が最適かを見てみましょう。私はあなたの工場のソリューションは、最もpythonicと自然なソリューションだと思う。 –

関連する問題