1

Let's say I want to replace some action of a class temporarily by applying some formula to something.action like this,

something.action = apply(something.action)

Later, I want to apply back the original action method to the instance something by doing something like this

something.action = ...

How should I accomplish this?

chanpkr
  • 895
  • 2
  • 10
  • 21
  • Are you absolutely sure the problem at hand cannot be solved using inheritance/wrapping rather than patching (messing with) objects? – Thijs van Dien Oct 19 '13 at 20:05

3 Answers3

8

I think you can simply save the original function and write

tmp = something.action
something.action = apply(something.action) 

and then, later

something.action = tmp

Example:

class mytest:
    def action(self):
        print 'Original'

a = mytest()
a.action()

tmp = a.action

def apply(f):
    print 'Not the ',
    return f

a.action = apply(a.action)
a.action()

a.action = tmp
a.action()

which gives

$ python test.py
Original
Not the  Original
Original
damienfrancois
  • 52,978
  • 9
  • 96
  • 110
  • I tried that, but I think by doing `something.action = apply(something.action)`, since tmp is bounded to something.action, tmp would change as well to the new applied action. – chanpkr Oct 19 '13 at 19:35
  • 3
    @Chan no it won't as long as "apply" does what it should do - creates copy of the something.action and returns it. If it changes action "in place", than it is wrongly used as a function instead of in place procedure, and then the whole information is lost so you need to copy the function: http://stackoverflow.com/questions/6527633/how-can-i-make-a-deepcopy-of-a-function-in-python – lejlot Oct 19 '13 at 19:43
  • @lejlot Oh.. So how do you copy a function? – chanpkr Oct 19 '13 at 19:53
  • 1
    Functions are first-class objects in Python, like integers or strings. They are copied on assignment. – damienfrancois Oct 19 '13 at 20:00
0

Best way to do that is to store the action in the same object, but with a different name:

something._old_action = something.action
something.action = apply(something._old_action) # this way you can still use it
something.action = lambda x: print(x)           # or you can ignore it completely
do_some_stuff()
something.action = something._old_action

Note that we're storing the old action in the object and we can use it. By starting the name with _, we inform that this attribute is private (purely a convention, but it's all we have in Python)

Wojciech Ptak
  • 683
  • 4
  • 14
0

How about something like this rather than messing with your object?

class Original(object):
    def __init__(self):
        self.x = 42

    def hello(self):
        print self.x

class OriginalWrapper(Original):
    def __init__(self, original):
        self.__class__ = type(original.__class__.__name__,
                              (self.__class__, original.__class__), {})
        self.__dict__ = original.__dict__

    def hello(self):
        print self.x + 10

original = Original()
original.hello() #42
wrapped = OriginalWrapper(original)
wrapped.hello() #52
Thijs van Dien
  • 6,516
  • 1
  • 29
  • 48