3

__get__クライアントコードで便利に使用できるように、特定のタイプのデータに対して記述子を使用してthinkプロキシを作成しようとしています(例で最もよく示されています)。

class Value(object):
    def __init__(self, val):
        self.val = val
    def __get__(self, instance, owner):
        return self.val

class Container(object):
    x = Value(1)
    y = [ Value(2), Value(3) ]

c = Container()
assert c.x == 1
assert c.y[0] == 2 # fails.

今、私はほとんど失敗する理由を理解しているので、クライアントがそれにアクセスするときに単にValueオブジェクトに直接アクセスする必要があるようにデータをラップするという私の目標を達成するためのより良い方法があるかどうか疑問に思っています(実際には、メソッドはそれを返す前に__get__何かをします)self.val

詳細

私が取り組んでいる実際のケースは、セレンテストケースのPageObjectsとPageElementsの記述を支援するユーティリティコードです。私が提供したいのは、テスト作成者が次の形式のPageObjectsを作成するためのクリーンでシンプルな方法です。

class MyLogin(PageObject):
    username_text_box = PageElement(By.ID, "username")
    password_text_box = PageElement(By.ID, "password")
    submit_button = PageElement(By.CLASS_NAME, "login-button")

driver = webdriver.Firefox()
driver.get("http://mypage.com")
login_page = MyLogin(driver)
login_page.username_text_box.send_keys("username01")
login_page.password_text_box.send_keys("XXXX")
login_page.submit_button.click()

PageElementクラス内で実際のWebElementをフェッチするビジネスをカプセル化しようとしていますが、クライアントがPageElementオブジェクトにアクセスした後、WebElementにアクセスできるようにしたいと考えています。リストを持つことができるので、辞書はPageObjectインスタンスをより明確にし、関連するPageElementsをグループ化するのに役立ちます。

4

3 に答える 3

2

アレイアクセサーもプロキシする場合は、プロキシを追加する必要があります。これは、xにproperty()を使用する例です。これは単なる属性であり、yには配列プロキシアクセサーです。

self._xとself。_yは、真のバリューの内部のプライベートアクセサーです。

import functools

class array_proxy(object):
    def __init__(self, accessor):
        self.accessor = accessor

    def __getitem__(self, key):
        return self.accessor(key)

class Value(object):
    def __init__(self, val):
        self.val = val

class Container(object):
    def __init__(self):
        self.__x = Value(1)
        self.__y = [Value(2), Value(3)]
        self.y = array_proxy(functools.partial(Container.get_y_element, self))

    @property
    def x(self):
        val = self.__x.val
        # do stuff with val
        return val

    def get_y_element(self, key):
        val = self.__y[key].val
        # do stuff with val
        return val


c = Container()
assert c.x == 1
assert c.y[0] == 2

他の人にget_y_elementを直接使用するように強制できる場合は、プロキシするのが少し簡単になり、ユーザーがアクセスしたときに何が起こっているかがより明確になります。

于 2012-07-06T00:47:51.437 に答える
1

Python_noobの答えは良いです。

理解を容易にするために、より単純で一般的ではないものにすることができます。

問題は、記述子プロトコルがクラス属性で「機能」することです。配置したスニペットの例では、クラス属性はリストであり、その中のオブジェクトyではありません。Value

__getitem__実装するだけで、アイテムの呼び出しに置き換えるシーケンスクラスを作成できる場合は__get__、必要な動作を取得する必要があります。

class Value(object):
    def __init__(self, val):
        self.val = val
    def __get__(self, instance, owner):
        return self.val

class ValueList(list):
    def __getitem__(self, item):
        return list.__getitem__(self,item).__get__(self.instance, self.instance.__class__)

class Container(object):
    def __init__(self, *args, **kw):
        self.y = ValueList(self.__class__.y)
        self.y.instance = self
        # ...

    x = Value(1)
    y = [ Value(2), Value(3) ]

c = Container()
assert c.x == 1
assert c.y[0] == 2 # works.

シーケンスクラスには、それがどのインスタンスに属しているかを自動的に知る方法がないことに注意してください。したがって、これはインスタンス化時に明示的に設定する必要があります。(この例のValueは、そのメソッドで同じ運命に苦しんで__init__います。Containerインスタンスを認識していません)

于 2012-07-06T03:47:14.567 に答える
0

私はjsbuenoとpython_noobの両方が近づいている実装で解決しました。ただし、どちらの実装も、テスト作成者が単純な宣言型ページオブジェクトを記述できるようにするという私の基準を満たしていません。

import inspect
import weakref
class Value(object):
    def __init__(self, val):
        self.val = val
    def __get__(self, instance, owner):
        return self.val

def get_value_from_proxy(obj, inst):
    if isinstance(obj, Value):
        return obj.__get__(inst, inst.__class__)
    else:
        return obj 

class ValueList(list):
    def __init__(self, instance, *args, **kwargs):
        list.__init__(self, *args, **kwargs)
        self.instance = weakref.ref(instance)
    def __getitem__(self, idx):
        return get_value_from_proxy(list.__getitem__(self, idx), self.instance() )

class ValueDict(dict):
    def __init__(self, instance, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
        self.instance = weakref.ref(instance)
    def __getitem__(self, key):
        return get_value_from_proxy(dict.__getitem__(self, key), self.instance() )

class BaseContainer(object):
    def __init__(self):
        for el in inspect.getmembers(self):
            if isinstance(el[1],list):
                setattr(self, el[0], ValueList(self, el[1]))
            elif isinstance(el[1],dict):
                setattr(self, el[0], ValueDict(self, el[1]))


class Container(BaseContainer):
    x = Value(1)
    y = [ Value(2), Value(3) ]
    z = {"test":Value(4)}

c = Container()
assert c.x == 1
assert c.y[0] == 2
assert c.z["test"] == 4 
于 2012-07-06T13:45:37.620 に答える