2020年11月15日 星期日

[ Python 常見問題 ] Decorating Python class methods - how do I pass the instance to the decorator?

 Source From Here

Question
I have the following code. I'm decorating the foo() method in bar, using the dec_check class as a decorator:
  1. class dec_check(object):  
  2.   
  3.   def __init__(self, f):  
  4.     self.func = f  
  5.   
  6.   def __call__(self):  
  7.     print 'In dec_check.__init__()'  
  8.     self.func()  
  9.   
  10. class bar(object):  
  11.   
  12.   @dec_check  
  13.   def foo(self):  
  14.     print 'In bar.foo()'  
  15.   
  16. b = bar()  
  17. b.foo()  
When executing this I was hoping to see:
In dec_check.__init__()
In bar.foo()

But I'm getting "TypeError: foo() takes exactly 1 argument (0 given)" as .foo(), being an object method, takes self as an argument. I'm guessing problem is that the instance of bar doesn't actually exist when I'm executing the decorator code.

HowTo
You need to make the decorator into a descriptor -- either by ensuring its (meta)class has a __get__ method, or, way simpler, by using a decorator function instead of a decorator class (since functions are already descriptors). E.g.:
  1. def dec_check(f):  
  2.   def deco(*args, **kargs):  
  3.     print(f'In deco: *args={args}; **kargs={kargs}')  
  4.     f(*args, **kargs)  
  5.   return deco  
  6.   
  7. class bar(object):  
  8.   def __init__(self, age):  
  9.     self.age = age  
  10.   
  11.   @dec_check  
  12.   def foo(self, name):  
  13.     print(f'In bar.foo: Hello {name}, my age is {self.age}')  
  14.   
  15. b = bar(36)  
  16. b.foo('John')  
Execution output:
In deco: *args=(<__main__.bar object at 0x7fa4e67b9880>, 'John'); **kargs={}
In bar.foo: Hello John, my age is 36


沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...