2016-08-27 19 views
3

スレッドセーフなアクセスのためにintをラップするプロキシクラスを作成したいと考えています。組み込み型とは対照的に、プロキシクラスは変更可能であるため、インプレースでインクリメントすることができます。さて、私はそのクラスを外部からの通常の整数と同じように使いたいと思います。通常、Pythonの__getattr__はそれが非常に簡単に内部オブジェクトへの属性のアクセスを転送することができます:プロキシオブジェクトをラップする整数のように振る舞わせる方法は?

class Proxy: 

    def __init__(self, initial=0): 
     self._lock = threading.Lock() 
     self._value = initial 

    def increment(self): 
     with self._lock: 
      self._value += 1 

    def __getattr__(self, name): 
     return getattr(self._value, name) 

しかし、__getattr__ does not get triggered for magic methods私は整数のように動作するプロキシの必要など__add____rtruediv__、などです。これらのメソッドを自動的に生成する方法はありますか?そうでなければ、ラップされた整数オブジェクトにそれらを転送しますか?

+0

暗黙のルックアップは、公式ドキュメントに記載されている: '__getattr__'が動作しない理由をhttps://docs.python.org/3/reference/datamodel.html#special-lookup –

+1

@IljaEverilä私が知っていますこれは私の質問が求めていることではありません。私はメソッドを生成したり、転送したりする方法を求めています。あなたがそれをそのように見たいなら、回避策です。 – danijar

+1

あなたの質問に関連する:http://yauhen.yakimovich.info/blog/2011/08/12/wrapping-built-in-python-types/ – VPfB

答えて

2

@VPfBcommentsにリンクされているブログの投稿には、組み込み型のダンダーメソッドをプロキシするためのより一般的で徹底的な解決策がありますが、ここでは単純化されています。このような転送方法を作成する方法の理解に役立つことを願っています。

import threading 
import numbers 


def _proxy_slotted(name): 
    def _proxy_method(self, *args, **kwgs): 
     return getattr(self._value, name)(*args, **kwgs) 
    # Not a proper qualname, but oh well 
    _proxy_method.__name__ = _proxy_method.__qualname__ = name 
    return _proxy_method 

# The list of abstract methods of numbers.Integral 
_integral_methods = """ 
    __abs__ __add__ __and__ __ceil__ __eq__ __floor__ 
    __floordiv__ __int__ __invert__ __le__ __lshift__ 
    __lt__ __mod__ __mul__ __neg__ __or__ __pos__ __pow__ 
    __radd__ __rand__ __rfloordiv__ __rlshift__ __rmod__ 
    __rmul__ __ror__ __round__ __rpow__ __rrshift__ 
    __rshift__ __rtruediv__ __rxor__ __truediv__ __trunc__ 
    __xor__""".split() 

# The dunder, aka magic methods 
_Magic = type('_Magic',(), 
       {name: _proxy_slotted(name) 
       for name in _integral_methods}) 


class IntProxy(_Magic, numbers.Integral): 
    """ 
    >>> res = IntProxy(1) + 1 
    >>> print(type(res), res) 
    <class 'int'> 2 
    >>> print(IntProxy(2)/3) 
    0.6666666666666666 
    """ 

    def __init__(self, initial=0, Lock=threading.Lock): 
     self._lock = Lock() 
     self._value = initial 

    def increment(self): 
     with self._lock: 
      self._value += 1 

    def __getattr__(self, name): 
     return getattr(self._value, name) 
関連する問題