2

我有以下代码,其中大部分代码看起来很尴尬、令人困惑和/或间接,但其中大部分是为了演示我遇到问题的更大代码的部分。请仔细阅读

# The following part is just to demonstrate the behavior AND CANNOT BE CHANGED UNDER NO CIRCUMSTANCES
# Just define something so you can access something like derived.obj.foo(x)
class Basic(object):
    def foo(self, x=10):
        return x*x

class Derived(object):
    def info(self, x):
        return "Info of Derived: "+str(x) 
    def set(self, obj):
        self.obj = obj

# The following piece of code might be changed, but I would rather not
class DeviceProxy(object):
    def __init__(self):
        # just to set up something that somewhat behaves as the real code in question
        self.proxy = Derived()
        self.proxy.set(Basic())

    # crucial part: I want any attributes forwarded to the proxy object here, without knowing beforehand what the names will be
    def __getattr__(self, attr):
        return getattr(self.proxy, attr)

# ======================================
# This code is the only I want to change to get things work

# Original __getattr__ function
original = DeviceProxy.__getattr__

# wrapper for the __getattr__ function to log/print out any attribute/parameter/argument/...
def mygetattr(device, key):
    attr = original(device, key) 
    if callable(attr):
        def wrapper(*args, **kw):
            print('%r called with %r and %r' % (attr, args, kw))
            return attr(*args, **kw)
        return wrapper
    else:  
        print "not callable: ", attr
        return attr

DeviceProxy.__getattr__ = mygetattr


# make an instance of the DeviceProxy class and call the double-dotted function
dev = DeviceProxy()
print dev.info(1)
print dev.obj.foo(3) 

我想要的是捕获所有方法调用,DeviceProxy以便能够打印所有参数/参数等等。在给定的示例中,这在调用时效果很好info(1),所有信息都被打印出来。但是当我调用双点函数dev.obj.foo(3)时,我只得到这不是可调用的消息。

如何修改上述代码,以便在第二种情况下获得我的信息?只能修改下面的代码===

4

1 回答 1

3

您只有一个__getattr__ondev并且您希望在此期间可以__getattr__访问。这是不可能的。属性访问不是作为一个整体访问的“点函数”。属性访问序列(点)一次评估一个,从左到右。在您访问时,无法知道您以后会访问。该方法只知道您正在访问哪些属性,而不知道您以后可以访问该结果的哪些属性。foodev.obj.foodev.objfoodev.__getattr__dev

实现您想要的唯一方法是在obj. 你说你不能修改“Base”/“Derived”类,所以你不能那样做。理论上,您可以DeviceProxy.__getattr__不返回访问属性的实际值,而是将该对象包装在另一个代理中并返回该代理。但是,这可能会有点棘手,并使您的代码更难以理解和调试,因为您最终可能会将大量对象包装在瘦代理中。

于 2012-12-08T19:10:00.577 回答