我有两个类(我们称之为Working和ReturnStatement),我不能修改它们,但是我想用日志扩展这两个类。诀窍是,Working的方法返回一个ReturnStatement对象,所以新的mutantWorking对象也返回ReturnStatement,除非我可以将其强制转换为mutantreturnStatement。用代码说:
# these classes can't be changed
class ReturnStatement(object):
def act(self):
print "I'm a ReturnStatement."
class Working(object):
def do(self):
print "I am Working."
return ReturnStatement()
# these classes should wrap the original ones
class MutantReturnStatement(ReturnStatement):
def act(self):
print "I'm wrapping ReturnStatement."
return ReturnStatement().act()
class MutantWorking(Working):
def do(self):
print "I am wrapping Working."
# !!! this is not working, I'd need that casting working !!!
return (MutantReturnStatement) Working().do()
rs = MutantWorking().do() #I can use MutantWorking just like Working
print "--" # just to separate output
rs.act() #this must be MutantReturnState.act(), I need the overloaded method
预期结果:
我正在包装工作。
我在工作。
——
我正在包装退货声明。
我是一个返回声明。
有可能解决这个问题吗?我也很好奇这个问题是否也可以用PHP来解决。除非我得到一个有效的解决方案,否则我不能接受这个答案,所以请写下有效的代码来被接受。
最佳答案
其他答案已经解释过了,没有演员阵容。您可以使用decorator创建子类或使用额外的功能创建修改后的新类型。
这是一个完整的例子(归功于How to make a chain of function decorators?)。您不需要修改原始类。在我的示例中,原始类称为Working。
# decorator for logging
def logging(func):
def wrapper(*args, **kwargs):
print func.__name__, args, kwargs
res = func(*args, **kwargs)
return res
return wrapper
# this is some example class you do not want to/can not modify
class Working:
def Do(c):
print("I am working")
def pr(c,printit): # other example method
print(printit)
def bla(c): # other example method
c.pr("saybla")
# this is how to make a new class with some methods logged:
class MutantWorking(Working):
pr=logging(Working.pr)
bla=logging(Working.bla)
Do=logging(Working.Do)
h=MutantWorking()
h.bla()
h.pr("Working")
h.Do()
这将打印
h.bla()
bla (<__main__.MutantWorking instance at 0xb776b78c>,) {}
pr (<__main__.MutantWorking instance at 0xb776b78c>, 'saybla') {}
saybla
pr (<__main__.MutantWorking instance at 0xb776b78c>, 'Working') {}
Working
Do (<__main__.MutantWorking instance at 0xb776b78c>,) {}
I am working
另外,我想知道为什么你不能修改一个类。你试过了吗?因为,作为创建子类的替代方法,如果您感到有活力,几乎可以在适当的位置修改一个旧类:
Working.Do=logging(Working.Do)
ReturnStatement.Act=logging(ReturnStatement.Act)
更新:将日志记录应用于类的所有方法
正如你现在特别要求的。您可以循环所有成员,并将日志记录应用于所有成员。但是您需要为要修改的成员类型定义一个规则。下面的示例排除了名称中有_uuu的任何方法。
import types
def hasmethod(obj, name):
return hasattr(obj, name) and type(getattr(obj, name)) == types.MethodType
def loggify(theclass):
for x in filter(lambda x:"__" not in x, dir(theclass)):
if hasmethod(theclass,x):
print(x)
setattr(theclass,x,logging(getattr(theclass,x)))
return theclass
有了这些,您需要做的就是创建一个类的新的日志版本:
@loggify
class loggedWorker(Working): pass
或就地修改现有类:
loggify(Working)