我尝试创建一个跟踪装饰器来跟踪哪个方法得到了调用。 让我们先读代码。代码是用python2.7编写的
class Decor(object):
def __init__(self,cls):
self.cls=cls
def __call__(self,*arg):
self.instance = self.cls(*arg)
return self
def __getattr__(self,name):
print "attribute name of instance of class {} = {}".format(self.cls.__name__,name)
return getattr(self.instance,name)
@Decor
class Foo(object):
attr1 = 10
def __init__(self,value):
self.value = value
def method1(self):
self.method2()
print self
print "value={}".format(self.value)
def method2(self):
print "hi"
f=Foo(10)
print f
f.method1()
输出:
^{pr2}$我以为method2会被打印成method1。你能解释一下为什么method2没有打印出来吗?在
我不明白输出线4。它显示的是Foo对象而不是Decor对象。f是装饰对象,为什么self是Foo对象?请解释一下!在
请给我一个解决这个问题的建议。谢谢
My other answer解释了为什么现有代码不能工作,以及如何修复它(尽管我不确定它是如何解释的)。在
但是通常还有一种更简单的方法来完成您要做的事情:您可以对类进行monkeypatch,而不是包装它。当然,这意味着您必须使用^{} 而不是^{} ,并附带所有有关意外递归调用自己的常见警告:*
这可能会打印出比您想要的更多的例如,在} )。当然,你可以过滤掉任何你不想记录的名字。在
f = Foo(10)
期间,它将显示正在查找的__class__
属性(but not ^{这也有一些包装和委托没有的限制。它不能在旧样式的类上工作;你不能用它来动态包装内置或C扩展类;等等。另一方面,它确实意味着},而不是{}-样式。在
Foo
有自己的名称,docstring等,而不是Decor
,而不是{*请注意,文档中说您应该始终调用基类版本来访问}的原始版本,如果{}没有定义基类版本,那么它当然是基类版本。
__getattribute__
中的属性,但是在这种情况下,您希望调用{这里的问题是
Foo.instance1
内的self
是Foo
实例,而不是Decor
实例。在如果打印出
f.method1
本身,就可以看到这一点:它是一个绑定方法,其实例是f
:为什么?好吧,您返回了}被烘焙到绑定方法中。在
getattr(self.instance, 'method1')
,它的作用与self.instance.method1
相同,所以{因此,当
method1
代码查找self.method2
(或self.value
)时,它是在Foo
实例上查找它,因此您的代码不会运行。在如果您不明白,请尝试阅读How Methods Work。(如果您不想仅仅接受属性查找的魔力,请按照末尾的链接Descriptor HowTo Guide。)
因此,如果希望} 手动创建一个。(或者,一旦理解了描述符,就可以直接查找函数实现,然后手动调用它的
self
成为Decor
内的Decor
实例,则必须返回一个带有Decor
实例的绑定方法,而不是Foo
实例。您可以通过使用^{__get__
。)例如:
^{pr2}$(如果您想让它与classmethods、staticmethods、实例dict中存储的函数等非方法可调用项一起工作,那么它当然需要比
callable
更复杂的一点。)现在:
所以,当我们称之为:
相关问题 更多 >
编程相关推荐