0

パフォーマンス指向の typemylib.color.Hardwareと、それに対応するユーザーフレンドリーなと があるmylib.color.RGBとしmylib.color.HSBます。ユーザーフレンドリーな色がライブラリ関数に渡されると、 に変換されcolor.Hardwareます。現在は、渡された引数の型を調べることで実装されています。しかし、将来的には、対応する変換機能を提供する任意のタイプから受け入れて自動変換したいと考えています。たとえば、「otherlib.color.LAB」を実装するサードパーティ ライブラリ。

現在、私は次のようなプロトタイプで遊んでいます。

class somelib:
    class A(object):
        def __init__(self, value):
            assert isinstance(value, int)
            self._value = value
        def get(self):
            return self._value

class userlib:
    class B(object):
        def __init__(self, value):
            self._value = value
        def __toA(self):
            try: value = int(self._value)
            except: value = 0
            return somelib.A(value)
        __typecasts__ = {somelib.A: __toA}

def autocast(obj, cast_type):
    if isinstance(obj, cast_type): return obj
    try: casts = getattr(obj, '__typecasts__')
    except AttributeError: raise TypeError, 'type cast protocol not implemented at all in', obj
    try: fn = casts[cast_type]
    except KeyError: raise TypeError, 'type cast to {0} not implemented in {1}'.format(cast_type, obj)
    return fn(obj)

def printValueOfA(a):
    a = autocast(a, somelib.A)
    print 'value of a is', a.get()

printValueOfA(userlib.B(42.42)) # value of a is 42
printValueOfA(userlib.B('derp')) # value of a is 0

そして、これが私の 2 番目のプロトタイプです。邪魔にはなりませんが、より冗長です。

# typecast.py

_casts = dict()

def registerTypeCast(from_type, to_type, cast_fn = None):
    if cast_fn is None:
        cast_fn = to_type
    key = (from_type, to_type)
    global _casts
    _casts[key] = cast_fn

def typeCast(obj, to_type):
    if isinstance(obj, to_type): return obj
    from_type = type(obj)
    key = (from_type, to_type)
    fn = _casts.get(key)
    if (fn is None) or (fn is NotImplemented):
        raise TypeError, "type cast from {0} to {1} not provided".format(from_type, to_type)
    return fn(obj)

# test.py
from typecast import *
registerTypeCast(int, str)
v = typeCast(42, str)
print "result:", type(v), repr(v)

質問。同じ機能を持つライブラリは存在しますか? (私は車輪を再発明したくありませんが、私の google-fu は None を生成します。) または、より良い (おそらくより Pythonic な) アプローチを提案できますか?

編集: 2 番目のプロトタイプを追加しました。

4

1 に答える 1

1

コンポーネントのアーキテクチャと適応を探しています。Zope コンポーネント アーキテクチャでは、インターフェースとアダプターを登録できます。あるタイプから別のタイプへのコンバーターを検索するための中央レジストリ。値をターゲットの型に変換するアダプターが存在する限り、任意のオブジェクトを API に渡すことができます。

ターゲット タイプが必要とするインターフェイスを定義することから始めます。

from zope.interface import Interface, Attribute

class IHardware(Interface):
    """A hardware colour"""

    bar = Attribute("The bar value for the frobnar")

    def foo():
        """Foo the bar for spam and eggs"""

その後、任意のクラスがそのインターフェースを実装できます (そのようなクラスのインスタンスがインターフェースを提供します)。

from zope.interface import implements

class Hardware(object):
    implements(IHardware)

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

    def foo(self):
        return self.bar + ' and spam and eggs'

RGB クラスの場合は、アダプターを登録します。IRGBインターフェイスがあれば役立ちますが、必須ではありません。

 from zope.interface import implements
 from zope.component import adapts
 from zope.component import getGlobalSiteManager


 class RGB(object):
     def __init__(self, r, g, b):
         self.r, self.g, self.b = r, g, b


class RGBtoHardwareAdapter(object):
    implements(IHardware)
    adapts(RGB)

    def __init__(self, rgb_instance):
        self._rgb = rgb_instance
        self.bar = '{},{},{}'.format(rgb_instance.r, rgb_instance.g, rgb_instance.b)

    def foo(self):
        return self.bar + ' in rgb and spam and eggs'


 gsm = getGlobalSiteManager()
 gsm.registerAdapter(RGBtoHardwareAdapter)

IHardwareこれで、API は値を次のように「キャスト」する必要があります。

def some_api_call(hardware):
    hardware = IHardware(hardware)

それでおしまい。hardware値がインターフェイスを直接提供する場合は、そのまま返されます。IHardwareインスタンスの場合RGB、アダプタはレジストリで見つかります。アダプターが作成され (RGBtoHardwareAdapter(hardware)呼び出され) 、オブジェクトのようIHardwareに動作します。

Hardware()アダプターに実際のオブジェクトを返すようにすることもできます。上記の例では代わりにプロキシ オブジェクトが返されますが、原則は同じです。

Python の抽象基本クラスは、別の方向、つまりダックタイピングからインターフェイスにアプローチします。特定のオブジェクトが ABC のメソッドと属性に準拠しているかどうかをテストできます。ただし、適応は提供しません。

于 2013-10-02T07:30:32.207 に答える