2

私はpython koans を解決しています。34日までは何の問題もありません。

これが問題です:

プロジェクト: プロキシ クラスを作成する

この課題では、プロキシ クラスを作成します (1 つを以下で開始します)。任意のオブジェクトでプロキシ オブジェクトを初期化できる必要があります。プロキシ オブジェクトで呼び出された属性はすべて、ターゲット オブジェクトに転送する必要があります。各属性呼び出しが送信されると、プロキシは送信された属性の名前を記録する必要があります。

プロキシ クラスが開始されます。メソッド欠落ハンドラーとその他のサポート メソッドを追加する必要があります。Proxy クラスの仕様は AboutProxyObjectProject koan に記載されています。

注: これは、Ruby Koans の対応物であることに比べて少しトリッキーですが、実行できます。

これが今までの私の解決策です:

class Proxy(object):
    def __init__(self, target_object):
        self._count = {}
        #initialize '_obj' attribute last. Trust me on this!
        self._obj = target_object

    def __setattr__(self, name, value):pass


    def __getattr__(self, attr):
        if attr in self._count: 
            self._count[attr]+=1
        else: 
            self._count[attr]=1
        return getattr(self._obj, attr)

    def messages(self):
        return self._count.keys()

    def was_called(self, attr):
        if attr in self._count:
            return True
        else: False

    def number_of_times_called(self, attr):
        if attr in self._count:
            return self._count[attr]
        else: return False

このテストまで機能します:

def test_proxy_records_messages_sent_to_tv(self):
    tv = Proxy(Television())

    tv.power()
    tv.channel = 10

    self.assertEqual(['power', 'channel='], tv.messages())

tv.messages()は、テレビ オブジェクトではなく、プロキシ オブジェクトによって取得されるため['power']です。 メソッドを操作しようとしましたが、常に無限ループに陥ります。tv.channel=10
__setattr__

編集1:

私はこれを試しています:

def __setattr__(self, name, value):
        if hasattr(self, name):
            object.__setattr__(self,name,value)
        else: 
            object.__setattr__(self._obj, name, value)

しかし、最後のエントリのループでこのエラーが発生します。

RuntimeError: maximum recursion depth exceeded while calling a Python object


File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 60, in test_proxy_method_returns_wrapped_object
tv = Proxy(Television())                                                                                                                                     
File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 25, in __init__                                               
self._count = {}                                                                                                                                             
File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 33, in __setattr__                                            
object.__setattr__(self._obj, name, value)                                                                                                                   
File "/home/kurojishi/programmi/python_koans/python 2/koans/about_proxy_object_project.py", line 36, in __getattr__                                            
if attr in self._count:      

ループは にあり__getattr__ます。

4

7 に答える 7

6

hasattrinを使用し__setattr__て、ローカルまたはプロキシされたオブジェクトに書き込む必要があるかどうかを決定しています。これは、1 つのケースを除くすべてのケースでうまく機能します。

あなた__init__には次の行があります:

  self._count = {}

この呼び出しは、その時点では存在__setattr__しないため、プロキシされたオブジェクトに転送されます'_count'(したがって、hasattrが返されます)。False

あなたのアプローチを使用したい場合は、次の__init__ように書く必要があります。

def __init__(self, target_object):
    object.__setattr__(self, '_count', {})
    #initialize '_obj' attribute last. Trust me on this!
    object.__setattr__(self, '_obj', target_object)
于 2012-06-19T08:17:14.943 に答える
1

テストから、プロキシを介してすべての属性呼び出しをログに記録することがプロキシの要件です。また、プロキシには、ロギングに例外的に使用される組み込みメソッドがほとんどないため、私の答えは次のとおりです。

class Proxy(object):

    def __init__(self, target_object):
        self.logs=[]
        self._obj = target_object


    def __getattribute__(self, attrname):
        if attrname in ['_obj','logs','messages','was_called','number_of_times_called'] :
            return object.__getattribute__(self, attrname)
        else:
            self.logs.append(attrname)
            return object.__getattribute__((object.__getattribute__(self, '_obj')), attrname)


    def __setattr__(self, name, value):
        if hasattr(self, '_obj'):
            self.logs.append(name)
            object.__setattr__(object.__getattribute__(self,'_obj'), name, value)
        else :
            object.__setattr__(self, name, value)

この後、他のメソッド('messages'、'was_called'、...)を実装するのは非常に簡単です。

古い質問を壊してすみません。

getattributeを変更できることがわかりました。属性がターゲットオブジェクトにあるかどうかを確認するだけです。

def __getattribute__(self, attrname):
        if attrname not in dir(object.__getattribute__(self, '_obj')):
            return object.__getattribute__(self, attrname)
        else:
            self.logs.append(attrname)
            return object.__getattribute__((object.__getattribute__(self, '_obj')), attrname)
于 2012-10-05T03:15:22.623 に答える
1

setattr はすべての割り当てで呼び出されます。getattr というより getattribute に似ています。これは __init__ メソッドのコードにも影響します。

つまり、このコードの最初のブランチはほとんどの場合失敗し、オブジェクトから継承された属性のみがテストに合格します。

def __setattr__(self, name, value):
    if hasattr(self, name):
        object.__setattr__(self,name,value)
    else: 
        object.__setattr__(self._obj, name, value)

代わりに、_obj 属性がない限り、代入はプロキシ用であると想定できます。したがって、__init__ のコメント。プロキシの属性を設定し、ターゲット オブジェクトを追加すると、今後のすべての割り当てがそれに送信されます。

def __setattr__(self, name, value):
    if hasattr(self, '_obj'):
        object.__setattr__(self._obj, name, value)
    else:
        object.__setattr__(self, name, value)

しかし、hasattr を使用することで、再帰を防ぐために __getattr__ を変更して _obj をチェックする必要もあります。

def __getattr__(self, name):
    if '_obj' == name:
        raise AttributeError

    if attr in self._count: 
        self._count[attr]+=1
    else: 
        self._count[attr]=1
    return getattr(self._obj, attr)

別の方法は、プロキシの __dict__ 属性を __setattr__ メソッドで直接検査することです。

def __setattr__(self, name, value):
    if '_obj' in self.__dict__:
    ...
于 2012-01-11T21:34:05.483 に答える
0

私がしたことは、プロキシ内の属性へのすべての呼び出しを取得し、object.__getattribute__再帰を避けるために経由で呼び出すことでした。

これはメソッドでは機能しなかったため、メソッド呼び出しを try..except AttributeError でラップして、最初にプロキシで試してみました。エラーが発生した場合は、子オブジェクトで試してください。

誰かがよりエレガントなソリューションを持っている場合は、それを見てみたい.

from runner.koan import *
コレクションインポートカウンターから

クラスプロキシ(オブジェクト):
    def __init__(self, target_object):
        self._messages=[]
        self._obj = target_object

    定義メッセージ (自己):
        self._messages を返す

    def was_called (自己、メッセージ):
        self._messages でメッセージを返す

    def number_of_times_called(自分自身、メッセージ):
        _count = Counter(self._messages).get(メッセージ)
        _カウントの場合:
            return _count
        else: # catch なし
            0 を返す

    def __getattribute__(self, attr_name):
        try: # 自分自身を呼び出す
            retval = object.__getattribute__(self, attr_name)
        except AttributeError: # 子オブジェクトの呼び出し
            retval = self._obj.__getattribute__(attr_name)
            object.__getattribute__(self, '_messages').append(attr_name)

        戻り値を返す

    def __setattr__(self, attr_name, attr_value):
        if hasattr(self, '_obj'): # 子オブジェクトを呼び出してメッセージをログに記録する
            self._obj.__setattr__(attr_name, attr_value)
            attr_name += "="
            object.__getattribute__(self, '_messages').append(attr_name)
        else: # __init__ で_obj を設定する前にこれを使用
            object.__setattr__(self, attr_name, attr_value)

    定義メッセージ (自己):
        self._messages を返す


于 2012-06-03T03:02:17.217 に答える
0
class Proxy(object):
   """Proxy class wraps any other class, and adds functionality to remember and report all messages called.
Limitations include that proxy blocks all direct subclass calls to:
messages, number_of_times_called, was_called, _obj, and _message_counts.
These calls must be made directly like my_proxy_instance._obj.messages.
"""


def __init__(self, target_object):
    print 'initializing a proxy for ' + target_object.__class__.__name__
    # WRITE CODE HERE
    self._message_counts = Counter();
    #initialize '_obj' attribute last. Trust me on this!
    self._obj = target_object

# WRITE CODE HERE                                   
def  __getattr__(self, attr_name):
    print 'getting an attribute: "' + attr_name + '" from "' + self._obj.__class__.__name__  + '"'
    self._message_counts[attr_name] += 1
    print self._message_counts
    return object.__getattribute__(self._obj, attr_name)

#def __getattribute__(self, attr_name):
#    print "intercepted!~ " + attr_name
#    object.__getattribute__(self, attr_name)

def __setattr__(self, attr_name, value):
    if((attr_name == '_obj') | (attr_name == '_message_counts')): # special proxy attributes.
        print 'setting the PROXY attribute: "' + attr_name + '"'
        object.__setattr__(self, attr_name, value)
    else:
        print 'setting the REAL attribute: "' + attr_name + '"'
        self._message_counts[attr_name+"="] += 1
        object.__setattr__(self._obj, attr_name, value)

def messages(self):
    return self._message_counts.keys()

def number_of_times_called(self, attr_name):
    return self._message_counts[attr_name]

def was_called(self, attr_name):
    return attr_name in self._message_counts
于 2012-02-04T02:16:33.433 に答える