How to cast object in Python
Question: 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.


Answer: 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](http://stackoverflow.com/questions/739654/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)
    

