5

不自然な例として、Python でランダムなフルーツ バスケットを生成するとします。バスケットを作成します。

basket = FruitBasket()

ここで、バスケットに含まれる果物の特定の組み合わせを指定したいと思います。私が非常にうるさい男で、バスケットがリンゴとザクロ、オレンジとグレープフルーツ、またはバナナだけでいっぱいである必要があるとします。

Python 演算子のオーバーロードについて調べていたのですが、必要な動作を定義__or____and__て取得できるようです。私はこのようなことができると思います:

basket.fruits = (Apple() & Pomegranate()) | (Banana()) | (Orange() & Grapefruit())

これは、2 つのクラス (OrAnd) を作成するのに問題なく機能します。__or__orが呼び出されると、新しいorオブジェクト__and__を返すだけです。OrAnd

def __or__(self, other):
    return Or(self, other)

def __and__(self, other):
    return And(self, other)

私が理解しようとしているのは、最初に果物をインスタンス化することなくこれを行うにはどうすればよいですか? 基本クラスで静的__or__メソッドを使用できないのはなぜですか? Fruit私はこれを試しましたが、うまくいきません:

class Fruit(object):
    @classmethod
    def __or__(self, other):
        return Or(self, other)

そして果物を割り当てる:

basket.fruits = (Apple & Pomegranate) | (Orange & Grapefruit) | (Banana)

次のようなエラーが表示されます。

TypeError: unsupported operand type(s) for |: 'type' and 'type'

これを機能させる方法について何か考えはありますか?

4

2 に答える 2

5

__or__オブジェクトのタイプで検索されます。たとえばFruit、次のようになりFruitます。のためFruitに、それはtypeです。Fruitただし、メタクラスを使用してのタイプを変更できます。

class FruitMeta(type):

    def __or__(self, other):
        return Or(self, other)


class Fruit(object):
    __metaclass__ = FruitMeta

(Python 3 の場合、構文はclass Fruit(metaclass=FruitMeta):代わりに です。)

これで、必要なことはすべて実行されます。Apple | Banana(これら 2 つが のサブクラスであると仮定するとFruit) が生成されOr(Apple, Banana)ます。

ただし、この種の設計には十分注意してください。それは魔法の領域に向かう傾向があり、簡単に混乱を引き起こす可能性があります.

(Python 2.7 での完全なデモ:)

>>> class Or(object):
...     def __init__(self, a, b):
...             self.a = a
...             self.b = b
...     def __repr__(self):
...             return 'Or({!r}, {!r})'.format(self.a, self.b)
... 
>>> class FruitMeta(type):
...     def __or__(self, other):
...             return Or(self, other)
... 
>>> class Fruit(object):
...     __metaclass__ = FruitMeta
... 
>>> class Apple(Fruit): pass
... 
>>> class Banana(Fruit): pass
... 
>>> Apple | Banana
Or(<class '__main__.Apple'>, <class '__main__.Banana'>)
于 2013-02-21T17:57:54.653 に答える
1

特別な (フック) メソッドをクラス メソッドとしてクラスに追加することはできません。それらは常に現在のオブジェクトの型で検索されるためです。クラスにあるインスタンスの場合、クラスの場合はtype代わりに検索されます。その理由についての動機については、この以前の回答を参照してください。

つまり、代わりにこれをメタクラスに実装する必要があります。メタクラスはクラスの型として機能します。

class FruitMeta(type):
    def __or__(cls, other):
        return Or(cls, other)

    def __and__(cls, other):
        return And(cls, other)

次に Python 3 の場合:

class Fruit(metaclass=FruitMeta):

または Python 2:

class Fruit(object):
    __metaclass__ = FruitMeta
于 2013-02-21T17:48:00.583 に答える