IronPython中的代理对象
我正在尝试在IronPython中创建一个代理对象,这个对象应该能够动态地展示底层的结构。这个代理本身不应该有任何功能和属性,我想在运行时捕捉所有的调用。捕捉函数调用很简单,我只需要为我的对象定义一个getattr()函数,检查底层是否存在相应的函数,然后返回一个类似函数的对象。
我在处理属性时遇到了问题——我不知道如何区分调用的上下文,也就是我的属性是作为左值(lvalue)还是右值(rvalue)被调用:
o = myproxy.myproperty # 我需要调用 underlying.myproperty_get()
或者
myproxy.myproperty = o # 我需要调用 underlying.myproperty_set(o)
我查看了Python中的特殊函数列表,但没有找到合适的东西。
我还尝试在对象中动态创建属性,结合使用exec()和内置的property()函数,但我发现IronPython 1.1.2缺少整个'new'模块(这个模块在IronPython 2.x beta中有,但我更倾向于使用IP 1.x,因为它支持.NET 2.0框架)。
有没有什么想法?
2 个回答
2
试试这个:
class Test(object):
_test = 0
def test():
def fget(self):
return self._test
def fset(self, value):
self._test = value
return locals()
test = property(**test())
def greet(self, name):
print "hello", name
class Proxy(object):
def __init__(self, obj):
self._obj = obj
def __getattribute__(self, key):
obj = object.__getattribute__(self, "_obj")
return getattr(obj, key)
def __setattr__(self, name, value):
if name == "_obj":
object.__setattr__(self, name, value)
else:
obj = object.__getattribute__(self, "_obj")
setattr(obj, name, value)
t = Test()
p = Proxy(t)
p.test = 1
assert t.test == p.test
p.greet("world")
2
你想要的在Python中的常见实现方式是这样的:
class CallProxy(object):
'this class wraps a callable in an object'
def __init__(self, fun):
self.fun = fun
def __call__(self, *args, **kwargs):
return self.fun(*args, **kwargs)
class ObjProxy(object):
''' a proxy object intercepting attribute access
'''
def __init__(self, obj):
self.__dict__['_ObjProxy__obj'] = obj
def __getattr__(self, name):
attr = getattr(self.__obj, name)
if callable(attr):
return CallProxy(attr)
else:
return attr
def __setattr__(self, name, value):
setattr(self.__obj, name, value)
我写了一个测试来证明这个行为是符合预期的:
#keep a list of calls to the TestObj for verification
call_log = list()
class TestObj(object):
''' test object on which to prove
that the proxy implementation is correct
'''
def __init__(self):
#example attribute
self.a = 1
self._c = 3
def b(self):
'example method'
call_log.append('b')
return 2
def get_c(self):
call_log.append('get_c')
return self._c
def set_c(self, value):
call_log.append('set_c')
self._c = value
c = property(get_c, set_c, 'example property')
def verify(obj, a_val, b_val, c_val):
'testing of the usual object semantics'
assert obj.a == a_val
obj.a = a_val + 1
assert obj.a == a_val + 1
assert obj.b() == b_val
assert call_log[-1] == 'b'
assert obj.c == c_val
assert call_log[-1] == 'get_c'
obj.c = c_val + 1
assert call_log[-1] == 'set_c'
assert obj.c == c_val + 1
def test():
test = TestObj()
proxy = ObjProxy(test)
#check validity of the test
verify(test, 1, 2, 3)
#check proxy equivalent behavior
verify(proxy, 2, 2, 4)
#check that change is in the original object
verify(test, 3, 2, 5)
if __name__ == '__main__':
test()
这个代码在CPython上运行时,没有任何断言抛出异常。IronPython应该是一样的,如果不是,那就说明它有问题,这个测试应该加入到它的单元测试中。