装饰算子python3.5
Posted
技术标签:
【中文标题】装饰算子python3.5【英文标题】:Decorate operators python3.5 【发布时间】:2017-04-07 01:25:06 【问题描述】:我正在尝试装饰类中的所有方法,并且我成功使用了此代码,但我也尝试记录对 * + - /
等运算符的调用,有没有办法装饰它们或类似 getattr(self,"*")
的东西记录通话?
class Logger(object):
def __init__(self, bool):
self.bool = bool
def __call__(self, cls):
class DecoratedClass(cls):
def __init__(cls, *args, **kwargs):
super().__init__(*args, **kwargs)
if not(self.bool):
return
methods = [func for func in dir(cls)
if callable(getattr(cls, func))
and not func.startswith("__class")]
for func in methods:
old_func = getattr(cls, func)
def decorated_function(fname, fn):
def loggedFunction(*args, **kwargs):
print("Calling 0 from 3 with params 1 and kwargs 2".format(fname.upper(), args, kwargs, cls))
return fn(*args, **kwargs)
return loggedFunction
setattr(cls, func, decorated_function(func, old_func))
return DecoratedClass
@Logger(True)
class DummyClass():
def __init__(self,foo):
self.foo = foo
def bar(self):
print(self.foo)
def __mul__(self,other):
print("Hello",other)
if __name__ == '__main__':
a = DummyClass('hola')
a.method()
a.__mul__(a) #this is logged
print(a*a) #this is not logged by decorator
【问题讨论】:
【参考方案1】:感谢 Łukasz,这是一个工作脚本。
我遇到的一个困难是处理多个实例,避免多次装饰同一个类方法。为了解决这个问题,我会跟踪修饰类方法 (cls.__logged
)。
另一个困难是处理诸如__setattr__
、__getattribute__
、__repr__
之类的魔术方法...我的解决方案是忽略它们,除了您必须在开始时定义的列表 (loggable_magic_methods
) .
from functools import wraps
loggable_magic_methods = ['__mul__',]
def is_magic_method(method):
return method.startswith('__')
class Logger(object):
def __init__(self, bool):
self.bool = bool
def __call__(self, cls):
class LoggedClass(cls):
cls.__logged = []
def __init__(instance, *args, **kwargs):
super().__init__(*args, **kwargs)
if not(self.bool):
return
methods = [funcname for funcname in dir(instance)
if callable(getattr(instance, funcname))
and (funcname in loggable_magic_methods or not is_magic_method(funcname))]
def logged(method):
@wraps(method)
def wrapper(*args, **kwargs):
print (method.__name__, args, kwargs, cls)
return method(*args, **kwargs)
return wrapper
for funcname in methods:
if funcname in cls.__logged:
continue
if is_magic_method(funcname):
setattr(cls, funcname, logged(getattr(cls, funcname)))
cls.__logged.append(funcname)
else:
setattr(instance, funcname, logged(getattr(instance, funcname)))
return LoggedClass
@Logger(True)
class DummyClass():
def __init__(self, foo, coef):
self.foo = foo
self.coef = coef
def bar(self):
print(self.foo)
def __mul__(self, other):
print(self.foo)
print(other.foo)
return self.coef * other.coef
if __name__ == '__main__':
a = DummyClass('hola', 1)
a.bar()
print()
print(a.__mul__(a))
print()
print(a*a)
print()
b = DummyClass('gracias', 2)
b.bar()
print()
print(b.__mul__(a))
print()
print(b*a)
【讨论】:
【参考方案2】:目前您正在修补实例上的值。您在 __init__
签名中使用 cls
是错误的朋友 - 实际上在这种情况下它是旧的普通 self
。
如果您想覆盖魔法方法,解释器会在类对象上而不是在实例上查找它们。
小例子:
class DummyClass:
def __init__(self, foo):
self.foo = foo
def __mul__(self, other):
return self.foo * other.foo
def logged(method):
def wrapper(*args, **kwargs):
print (method.__name__, args, kwargs)
return method(*args, **kwargs)
return wrapper
DummyClass.__mul__ = logged(DummyClass.__mul__)
a = DummyClass(1)
b = DummyClass(2)
assert a * a == 1
assert a * b == 2
assert b * b == 4
每个通话都会被记录。
>>> a = DummyClass(1)
>>> b = DummyClass(2)
>>> assert a * a == 1
__mul__ (<__main__.DummyClass object at 0x00000000011BFEB8>, <__main__.DummyClass object at 0x00000000011BFEB8>)
>>> assert a * b == 2
__mul__ (<__main__.DummyClass object at 0x00000000011BFEB8>, <__main__.DummyClass object at 0x00000000011BF080>)
>>> assert b * b == 4
__mul__ (<__main__.DummyClass object at 0x00000000011BF080>, <__main__.DummyClass object at 0x00000000011BF080>)
我会把重写猴子修补方法的任务留给你。
【讨论】:
以上是关于装饰算子python3.5的主要内容,如果未能解决你的问题,请参考以下文章