如何在Python中强制转换对象

如何在Python中强制转换对象,python,inheritance,casting,Python,Inheritance,Casting,我有两个类(我们称它们为Working和ReturnStatement),我不能修改它们,但我想通过日志来扩展它们。诀窍在于,Working的方法返回一个ReturnStatement对象,因此新的MutantWorking对象也返回ReturnStatement,除非我可以将其转换为MutantReturnStatement。用密码说: # these classes can't be changed class ReturnStatement(object): def act(sel

我有两个类(我们称它们为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解决。除非我得到了一个有效的解决方案,否则我无法接受答案,所以请编写有效的代码以获得接受。

Python中没有“强制转换”。 类的任何子类都被视为其父类的实例。通过正确调用超类方法和重写类属性,可以实现所需的行为

更新:随着静态类型检查的出现,出现了“类型转换”-下面的检查

在您的示例中,您可以做的是,必须有一个子类初始值设定项来接收超类并复制其相关属性-因此,您的MutantReturnstatement可以这样编写:

class MutantReturnStatement(ReturnStatement):
    def __init__(self, previous_object=None):
        if previous_object:
            self.attribute = previous_object.attribute
            # repeat for relevant attributes
    def act(self):
        print "I'm wrapping ReturnStatement."
        return ReturnStatement().act()
然后将您的MutantWorking类更改为:

class MutantWorking(Working):
    def do(self):
        print "I am wrapping Working."
        return MutantReturnStatement(Working().do())
如果要复制大量(如超过3:-)属性,则可以通过Pythonic方法在
\uuuu init\uuuu
方法上避免大量的
self.attr=other.attr
行- 其中最懒的一个就是复制另一个实例的
\uu dict\uu
属性

或者,如果您知道自己在做什么,您也可以简单地将目标对象的
\uuuuu class\uuuuu
属性更改为所需的类,但这可能会产生误导,并导致细微错误(子类的
\uuuuu init\uuuuu
方法不会被调用,对非python定义的类和其他可能的问题不起作用),我不建议使用这种方法-这不是“强制转换”,而是使用内省来强制执行对象更改,只是为了保持答案完整:

class MutantWorking(Working):
    def do(self):
        print "I am wrapping Working."
        result = Working.do(self)
        result.__class__ = MutantReturnStatement
        return result
        
再一次-这应该有效,但不要这样做-使用前一种方法

顺便说一句,我对其他允许强制转换的OO语言不是很有经验,但是在任何语言中都允许对子类进行强制转换吗?这有意义吗?我认为强制转换只允许对父类进行

更新:当一个人以PEP 484中描述的方式处理类型暗示和静态分析时,有时静态分析工具无法了解发生了什么。因此,有
键入.cast调用:它在运行时完全不做任何事,只返回传递给它的相同对象,但工具随后“学习”返回的对象是传递的类型,不会对此进行抱怨。它将删除helper工具中的键入错误,但我不能强调它在运行时没有任何影响:

[18]中的
:从键入import cast开始
In[19]:cast(int,3.4)
Out[19]:3.4
没有直接的方法

您可以这样定义mutatreturn语句的init

def __init__(self, retStatement):
    self.retStatement = retStatement
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())
然后像这样使用它:

def __init__(self, retStatement):
    self.retStatement = retStatement
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())
您应该避免在包装器中继承ReturnStatement,如下所示

class MutantReturnStatement(object):
    def act(self):
        print "I'm wrapping ReturnStatement."
        return self.retStatement.act()

正如其他答案已经解释的那样,没有强制转换。您可以使用装饰器来创建子类或修改具有额外功能的新类型

这里有一个完整的例子(归功于)。您不需要修改原始类。在我的示例中,原始类称为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
更新:将日志记录应用于类的所有方法

正如您现在特别要求的那样。您可以循环所有成员并将日志记录应用于所有成员。但您需要为要修改的成员类型定义一个规则。下面的示例排除了名称中带有_u的任何方法

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
或在适当位置修改现有类:

Working.Do=logging(Working.Do)
ReturnStatement.Act=logging(ReturnStatement.Act)
loggify(Working)

你不需要在这里施展才华,你只需要

class MutantWorking(Working):
def do(self):
    print "I am wrapping Working."
    Working().do()
    return MutantReturnStatement()

这显然会给出正确的返回和所需的打印输出。

您所做的不是强制转换,而是类型转换

def cast_to(mytype: Type[any], obj: any):
    if isinstance(obj, mytype):
        return obj
    else:
        return mytype(obj)

class MutantReturnStatement(ReturnStatement):
    def __init__(self, *args, **kwargs):
        if isinstance(args[0], Working):
            pass  
            # your custom logic here 
            # for the type conversion.
用法:

cast_to(MutantReturnStatement, Working()).act()
# or simply
MutantReturnStatement(Working()).act()

(请注意,在您的示例中,
mutatreturnstatement
没有
.do()
成员函数。)

Python中不存在“Casting”。此外,您不应该执行“
ReturnStatement().act()
”-如果希望其他类上的act方法处理当前对象,请执行
ReturnStatement.act(self)
-或者只将其标记为classmethod或staticmethod-如果不需要当前对象的实例。Working.do()返回ReturnStatement。我想要MutantWorking.do()我知道Python中不存在强制转换,但问题是存在的。有解决方案吗?我重写MutantReturnStatement的_init__()方法来完成额外的工作并使用ReturnStatement返回,还是重写MutantReturnStatement的act()都无关紧要方法来完成ReturnStatement的act()方法的工作。我无法访问MutantReturnStatement,因为使用ReturnStatement返回,而不是使用MutantReturnStatement。我是python新手,代码中可能有一些错误,但它显示了与您的答案类似的想法!如果没有人告诉其他(更好)技术,我将接受此:).+1. @维斯科,+1,如果你喜欢的话。(你可以不止一次地这么做。)而且,使用装饰器,你可以做到这一点,而不需要为每个方法生成一个这样的代码块。这个解决方案仍然不完美。我没提到我需要翻译,我必须带着翻译回来