10

クラスにプラグインできるメソッドを使用して、軽量のインターフェイスを作成したいと思います。これがScalaの短い例です:

class DB {
  def find(id: String) = ...
}

trait Transformation extends DB {
  def transform(obj: String): String

  override def find(id: String) =
    transform(super.find(id))
}

trait Cache extends DB {
  val cache = Cache()
  override def find(id: String) = {
    ...
    if (cache.contains(id))
       cache.find(id)
    else {
       cache.set(id, super.find(id))
       cache.get(id)
    }
  }   
}

これらのクラス(特性)を使用して、Transformation、Cache、またはその両方を使用してDBクラスをインスタンス化できます。Transformationには抽象メソッドtransformがあり、それでも具象クラスに実装する必要があることに注意してください。

new DB() with Transformation {
  def transform(obj: String): obj.toLower()
}
new DB() with Cache
new DB() with Transformation with Cache {
  def transform(obj: String): obj.toLower()
}

Pythonでこのようなことを実現する方法はありますか?Python用のTraitsパッケージが存在することは知っていますが、その目的は異なっているようです。

4

4 に答える 4

12

最も簡単な解決策は、おそらく別のサブクラスを作成することです。

# assuming sensible bases:
class DB(object):
    ...

class Transformation(object):
    def transform(self, obj):
        ...

    def get(self, id):
        return self.transform(super(Transformation, self).get(id))

class Cache(object):
    def __init__(self, *args, **kwargs):
        self.cache = Cache()
        super(Cache, self).__init__(*args, **kwargs)
    def get(self, id):
        if id in self.cache:
            return self.cache.get(id)
        else:
            self.cache.set(id, super(Cache, self).get(id))
            return self.cache.get(id)

class DBwithTransformation(Transformation, DB):
    # empty body
    pass

クラスに実際に名前を付けることを頑固に拒否する場合は、type直接呼び出すことができます。交換

class DBwithTransformation(Transformation, DB):
    pass

db = DBwithTransformation(arg1, arg2, ...)

db = type("DB", (Transformation, DB), {})(arg1, arg2, ...)

これはScalaの例よりもそれほど悪くはありません。

Python型システムの微妙さのために、プライマリクラス(DB)から継承しないミックスインがベースリストの最初に表示されます。そうしないと、ミックスインクラスがプライマリ基本クラスのメソッドを適切にオーバーライドできなくなります。

その同じ微妙さにより、追加の機能を適切な派生クラスにすることができます。ダイヤモンドの継承パターンは問題ではありません。基本クラスは、それらから継承する中間基本クラスの数に関係なく、一度だけ表示されます(結局、それらはすべて最終的にから継承しobjectます)。

于 2011-06-05T00:06:57.967 に答える
5

Scalaの特性に最も近い解決策は、抽象基本クラスです。それらはabcモジュールで利用できます:

import abc

class Transformation(DB):
     __metaclass__ = abc.ABCMeta

     @abc.abstractmethod
     def transform(self, obj):
         pass

     def find(self, id):
         return self.transform(super(Transformation, self).get(id))

次に、メソッドを抽象化するための適切な実装を使用して、Transformationクラスをサブクラス化する必要があります。

NotImplementedErrorところで、抽象として必要なメソッドを上げるだけで、abcをシミュレートすることもできます。ABCMetaでは、抽象クラスのインスタンスを作成することはできません。

PS:Python 3の構文は両方のメタクラスに対応しておりsuper、少し異なります(さらに優れています!)。

于 2011-06-05T01:24:15.403 に答える
0

これは、クラスを使用した回答の代替手段です。実行時にトレイトを作成したい場合は、type()を悪用しましょう。

http://twitter.github.io/scala_school/basics.html#traitから例を見てください

Car = type('Car', (object,), {'brand': ''})
Shiny = type('Shiny', (object,), {'refraction': 0})

BMW = type('BMW', (Car, Shiny,), {'brand': 'BMW', 'refraction': 100})
my_bmw = BMW()

print my_bmw.brand, my_bmw.refraction

コンストラクターをに渡すこともできBMWます

def bmw_init(self, refraction):
    self.refraction = refraction

BMW = type('BMW', (Car, Shiny,), {'brand': 'BMW', '__init__': bmw_init})
c1, c2 = BMW(10), BMW(100)
print c1.refraction, c2.refraction
于 2013-10-11T12:19:15.040 に答える
-5

EnthoughtのPythonTraitsプロジェクトをご覧ください。しかし、あなたが説明していることは、通常のPythonプロパティと同じようです。

于 2011-06-05T00:04:09.533 に答える