0

私が最初に投稿した質問は不足していたので、ここに説明があります.

クラス内にインテリジェンスを持たせたいのですが、インスタンスを作成すると、そのインスタンスは、このクラスのサブクラスの 1 つである別のクラスであると判断されます。

より具体的には、学習課題として魔方陣ソルバーを作成しています。

  • MagicSquareMagicSquare のロジックを含むクラスが必要です。
  • これら 2 種類の魔方陣を解くロジックを含む、そのクラスのサブクラスがOddMagicSquare必要です。EvenMagicSquare
  • の作成を呼び出して、そのMagicSquareサイズを提供し、ジェネリックのトップクラスではなく、どのサブクラスのインスタンスを作成するかをn内部のインテリジェンスに決定させたいと考えています。MagicSquareMagicSquare

インスタンスを作成するサブクラス ( OddMagicSquare/ ) を決定するインテリジェンスは、 の外部にある可能性があることを理解しています(そうであれば、おそらく実装が簡単になるでしょう) 。中に入れたいのは、勘のせいかもしれません。ある魔方陣がどの種類の魔方陣であるかを決定するロジックは、クラスに属しているように見えるので、この方法でよりクリーンで整頓される予感があります。EvenMagicSquareMagicSquareMagicSquareMagicSquare

4

4 に答える 4

0

self.__class__最初に、変更中の回答に基づいた回答を提供しました__init__()。これは避けるべきだとコメントで説明されました。

今、私は基本クラスの再定義に基づいた答えを提供しています__new__

class Car(object):
    """The base class."""

    def __new__(cls, max_speed):
        if cls is Car and max_speed > 100:
            return object.__new__(SuperCar, max_speed)
        else:
            return object.__new__(cls, max_speed)

    def __init__(self, max_speed):
        self.max_speed = max_speed

class SuperCar(Car):
    """The sub class."""

    pass   

インスタンスの作成を担当するコードは、組み込みの in(1)__new__メソッドにあります。クラスが呼び出されたときに呼び出され (例: my_car = Car(100))、その呼び出しで指定された引数が渡されます。

aCarまたは aのインスタンスSuperCar化 ( の継承による__new__) が呼び出されると、再定義された は、作成されるインスタンスが であり、かつが 100 より大きい__new__かどうかをチェックします。cls Carmax_speed

SuperCarその場合、 の代わりに のインスタンスを作成し、それをCar返しobject.__new__(SuperCar, max_speed)ます。

__new__それ以外の場合は、このインスタンスを作成するために組み込みの通常のデフォルトを呼び出し、それを使用object.__new__(cls, max_speed)して返します。not max_speed > 100これは、予想されるケースと、この再定義__new__がサブクラスによって呼び出されるケースSuperCar(のように)をキャッチしmy_ferrari = SuperCar(250)ます。

記録のために、これが私の以前の答えです:

インスタンスの作成時に、ある条件に応じてインスタンスのクラスをそのサブクラスの 1 つに変更する場合は、次の__init__ように でいくつかのロジックを使用できます。

class Car(object):
    def __init__(self, max_speed_kph):
        if self.__class__ == Car:
            if max_speed_kph > 230:
                self.__class__ = SuperCar
                self.__init__()

class SuperCar(Car):
    def __init__(self):
        print 'this car is fast!'

これself.__init__()は、新しいクラスとしてインスタンスを再初期化するためのものです。

脚注:

  1. これは本当にビルトインですか?Python ドキュメントの「組み込み関数」トピックには表示されません。
于 2013-11-01T20:57:07.260 に答える
0

ここでサブクラスを誤用していると思います。

サブクラスは、サブタイプ (インターフェイスが目に見えて特殊化されているもの) を表すと想定されています。これは奇数対偶数魔方陣の場合には当てはまりません。どちらも同じメソッドを持ち、それらのメソッドに応答して同じ (呼び出し元から見える) ことを行います。

奇数の魔方陣と偶数の魔方陣の違いが何をするかではなく、どのように行うかである場合、それらはサブクラスではなく、複数のポリシーを持つ 1 つのクラスにすぎません。

奇数サブタイプと偶数サブタイプとは異なる方法で相互作用MagicSquareSolverする必要があるタイプをユーザーとする合理的なタイプが存在する場合があります。MagicSquareその場合、個別のポリシーを個別のクラスにする必要があります。それらを抽象基本クラスに基づいて作成することもできます(これは Python ではほとんど必要ありませんが、念のために示しておきます)。

class MagicSquareSolver(metaclass=abc.ABCMeta:
    def __init__(self, square):
        self.square = square
    @abc.abstractmethod
    def solve(self):
        pass

class OddMagicSquareSolver(MagicSquareSolver):
    def __init__(self, square):
        super().__init__(square)
        do_odd_specific_stuff(self)
    def solve(self):
        do_odd_specific_solution(self)

class EvenMagicSquareSolver(MagicSquareSolver):
    def __init__(self, square):
        super().__init__(square)
        do_even_specific_stuff(self)
    def solve(self):
        do_even_specific_solution(self)

class MagicSquare:
    def __init__(self, n):
        self.n = n
        self.cells = self.make_cells()
        if n % 2:
            self.solver = OddMagicSquareSolver(self)
        else:
            self.solver = EvenMagicSquareSolver(self)
    def solve(self):
        return self.solver.solve()

しかし、これでもやり過ぎの可能性が高いと思います。魔方陣の観点からも、単一のsolve方法を超えて、魔方陣を解くためのインターフェイスは何ですか? たとえば、解決プロセスを視覚化する、またはそれを GUI ゲームのヘルパーに変えることを計画している場合、その質問に対する答えがあるかもしれませんsolve_one_step(ただし、その場合でも、メソッドまたはsolveジェネレーター メソッドがすべてである可能性があります)。必要な場合は、オープン ソースの数独ゲームの例を参照してください)。しかし、おそらく何もありません。

そして、これがyossiの答え(および彼がリンクした暴言)が得ているものです:クラスのインターフェースが名前付きの単一のメソッドdo_it(またはクラス名自体とまったく同じ情報を持つより便利な名前)である場合、およびそのメソッドの呼び出しの外に存在する必要がある状態はありません。クラスはまったくありません。関数があり、ぎこちなく隠されています。一部の言語 (特に Java と C#) では、このようにぎこちなくする必要がありますが、Python はそうではありません。これを書くことができます:

class MagicSquare:
    def __init__(self, n):
        self.n = n
        self.fill_squares()
        self.cells = self.make_cells()
    def solve(self):
        if n % 2:
            return self._solve_odd()
        else:
            return self._solve_even()
    def _solve_odd(self):
        stuff()
    def _solve_even(self):
        other_stuff()
于 2013-11-05T19:10:29.253 に答える