如何在Python中投射对象 [英] How to cast object in Python
问题描述
我有两个类(我们称之为Working和ReturnStatement),我不能修改,但是我想用日志记录扩展它们。诀窍是Working's方法返回一个ReturnStatement对象,所以新的MutantWorking对象也返回ReturnStatement,除非我可以把它转换为MutantReturnStatement。使用代码:
#这些类不能更改
class ReturnStatement(object):
def act(self):
print我是一个ReturnStatement。
class Working(object):
def do(self):
printI'm Working。
return ReturnStatement()
#这些类应该包装原始的
class MutantReturnStatement(ReturnStatement):
def act(self):
print我包装ReturnStatement。
return ReturnStatement()。act()
class MutantWorking(Working):
def do(self):
print我正在包装工作。
#!!!这不工作,我需要铸造工作!
return(MutantReturnStatement)Working()。do()
rs = MutantWorking()do()#我可以使用MutantWorking类似Working
print - 只是为了分离输出
rs.act()#this必须是MutantReturnState.act(),我需要重载的方法
预期结果:
¥b $ b我正在包装工作。
我正在工作。
-
我包装ReturnStatement。
我是一个ReturnStatement。
是否可以解决问题?我也很好奇,如果问题可以解决在PHP,太。
有一个工作解决方案,没有铸造作为其他答案已经解释。
下面是一个完整的例子(信用了解Python装饰器)。你不需要修改你的原始类。在我的例子中,原始类称为Working。
#用于日志记录的装饰器
def logging(func):
def wrapper(* args,** kwargs):
print func .__ name__,args,kwargs
res = func(* args,** kwargs)
return res
返回包装器
#这是一些你不想/不能修改的示例类
class Working:
def Do(c):
print(I正在工作)
def pr(c,printit):#其他示例方法
print(printit)
def bla(c):#其他示例方法
c.pr saybla)
#这是如何使用一些方法记录一个新类:
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 __。0xb776b78c>上的MutantWorking实例),{}
pr < __ main __。在0xb776b78c的突变工作实例,'saybla'){}
saybla
pr(<__ main __。在0xb776b78c的突变工作实例,'Working'){}
工作
Do(< __ main __。在0xb776b78c>上的MutantWorking实例,{}
我正在工作
此外,我想了解为什么你不能修改类。你试过吗?因为,作为一个替代制作子类,如果你感觉动态,你可以几乎总是修改一个旧类的地方:
Working.Do = logging(Working.Do)
pre>
ReturnStatement.Act = logging(ReturnStatement.Act)
更新:将记录应用于某个类的所有方法
现在特别要求这个。您可以循环所有成员,并将日志记录应用到所有成员。但是你需要定义一个规则来修改什么类型的成员。下面的示例排除了名称中包含__的任何方法。
导入类型
def hasmethod(obj,name)
return hasattr(obj,name)和type(getattr(obj,name))== types.MethodType
def loggify(theclass):
for x in filter x:__不在x,dir(theclass)):
如果hasmethod(theclass,x):
print(x)
setattr(theclass,x,logging ,x)))
return theclass
类的新记录版本是:
@loggify
class loggedWorker(working):pass
或修改现有类别:
loggify(Working)
I have two classes (let's call them Working and ReturnStatement) which I can't modify, but I want to extend both of them with logging. The trick is that the Working's method returns a ReturnStatement object, so the new MutantWorking object also returns ReturnStatement unless I can cast it to MutantReturnStatement. Saying with code:
# 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
The expected result:
I am wrapping Working.
I am Working.
--
I'm wrapping ReturnStatement.
I'm a ReturnStatement.Is it possible to solve the problem? I'm also curious if the problem can be solved in PHP, too. Unless I get a working solution I can't accept the answer, so please write working code to get accepted.
解决方案There is no casting as the other answers already explained. You can make subclasses or make modified new types with the extra functionality using decorators.
Here's a complete example (credit to Understanding Python decorators). You do not need to modify your original classes. In my example the original class is called 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()
this will print
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
In addition, I would like to understand why you can not modify a class. Did you try? Because, as an alternative to making a subclass, if you feel dynamic you can almost always modify an old class in place:
Working.Do=logging(Working.Do) ReturnStatement.Act=logging(ReturnStatement.Act)
Update: Apply logging to all methods of a class
As you now specifically asked for this. You can loop over all members and apply logging to them all. But you need to define a rule for what kind of members to modify. The example below excludes any method with __ in its name .
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
With this all you have to do to make a new logged version of a class is:
@loggify class loggedWorker(Working): pass
Or modify an existing class in place:
loggify(Working)
这篇关于如何在Python中投射对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!