Is it possible monkey patch like this?

Discussion in 'Python' started by Marc Aymerich, Dec 18, 2012.

  1. Dear all,
    I want to monkey patch a method that has lots of code so I want to avoid copying all the original method for changing just two lines. The thing is that I don't know how to do this kind of monkey patching.

    Consider the following code:

    class OringinalClass(object):
    def origina_method(self, *args, **kwargs):
    ...
    if some_condition(): # This condition should be changed
    raise SomeException
    ...
    if some_condition():
    ...
    #if some_condition(local_variable): # This condition should be added
    # raise SomeException
    ...


    Is it possible to tell Python to run the original method without stopping when an exception is raised? so I can catch them on a wrapper method and apply my conditional there.

    Any other idea on how to monkey patch those two conditionals ?


    Thanks!
    Marc Aymerich, Dec 18, 2012
    #1
    1. Advertising

  2. On Tue, Dec 18, 2012 at 9:26 PM, Marc Aymerich <> wrote:
    > Any other idea on how to monkey patch those two conditionals ?


    Would it be plausible to simply add a parameter to the function that
    controls its behaviour? It'd be a lot more readable than fiddling from
    the outside ever would.

    ChrisA
    Chris Angelico, Dec 18, 2012
    #2
    1. Advertising

  3. Marc Aymerich

    Peter Otten Guest

    Marc Aymerich wrote:

    > Dear all,
    > I want to monkey patch a method that has lots of code so I want to avoid
    > copying all the original method for changing just two lines. The thing is
    > that I don't know how to do this kind of monkey patching.
    >
    > Consider the following code:
    >
    > class OringinalClass(object):
    > def origina_method(self, *args, **kwargs):
    > ...
    > if some_condition(): # This condition should be changed
    > raise SomeException
    > ...
    > if some_condition():
    > ...
    > #if some_condition(local_variable): # This condition should be
    > #added
    > # raise SomeException
    > ...
    >
    >
    > Is it possible to tell Python to run the original method without stopping
    > when an exception is raised?


    No.

    > so I can catch them on a wrapper method and
    > apply my conditional there.
    >
    > Any other idea on how to monkey patch those two conditionals ?


    One of the cleanest alternatives is to factor out the condition in the
    original class and then use a subclass:

    class Original:
    def method(self, *args, **kw):
    self.check_condition(...)
    ...
    def check_condition(self, ...):
    if condition:
    raise SomeException

    class Sub(Original):
    def check_condition(self, ...):
    pass

    If you insist on monkey-patching possible solutions depend on the actual
    conditions. If some_condition() is a function, replace that function. If it
    is actually an expression tweak the arguments. E. g:

    >>> class Original:

    .... def method(self, x):
    .... if x < 0: raise ValueError
    .... print x * x
    ....
    >>> Original().method(-2)

    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 3, in method
    ValueError
    >>> class Int(int):

    .... def __lt__(self, other): return False # a blunt lie
    ....
    >>> Original().method(Int(-2))

    4

    This tends to get complex quickly, so in the long run you will not be happy
    with that approach...
    Peter Otten, Dec 18, 2012
    #3
  4. Marc Aymerich

    Terry Reedy Guest

    On 12/18/2012 5:26 AM, Marc Aymerich wrote:

    > I want to monkey patch a method that has lots of code so I want to
    > avoid copying all the original method for changing just two lines.


    You omitted the most important piece of information. Can you modify the
    original code (or get someone else to do so) or must you leave it as is?
    Chris and Peter gave you answers for the former case. If the latter, you
    must copy and modify for the change you specified.

    --
    Terry Jan Reedy
    Terry Reedy, Dec 18, 2012
    #4
  5. On Tue, 18 Dec 2012 02:26:42 -0800, Marc Aymerich wrote:

    > Dear all,
    > I want to monkey patch a method that has lots of code so I want to avoid
    > copying all the original method for changing just two lines. The thing
    > is that I don't know how to do this kind of monkey patching.


    The only types of monkey-patching supported by Python are overriding or
    overloading. In the first, you override a function by replacing it with a
    new function of your own design; in the second, you save the original
    somewhere, then replace it with a new function that wraps the old:

    # overloading the len() function
    _len = len
    def len(obj):
    print "calling len on object %r" % obj
    print "returning result as a string"
    return str(_len(obj))


    You cannot monkey-patch in the middle of a function.

    Technically, you could hack the byte code of the function, but such a
    thing is not supported or documented anywhere. If you want to learn more,
    you can google on "python byte code hacks", but let me warn you that this
    is advanced, and dark, territory where you will get little or no help
    when things go wrong.


    > Consider the following code:
    >
    > class OringinalClass(object):
    > def origina_method(self, *args, **kwargs):
    > ...
    > if some_condition(): # This condition should be changed
    > raise SomeException


    If some_condition is a function or method call, you can patch the
    function or method. That may require subclassing another object. E.g.

    if args[2].startswith('spam'): ... # CHANGE ME

    instead of passing a string as args[2], you could subclass string to
    patch startswith, then pass a subclass instance instead of a string:

    result = instance.original_method(x, y, 'spam', z)

    becomes:

    result = instance.original_method(x, y, MyStr('spam'), z)

    You could even patch original_method to automatically MyStr-ify args[2].

    But in general, if the condition is an arbitrary expression:

    if x < y or z > 2 and spam is not None: # CHANGE ME

    there is nothing you can do except replace the entire method.

    > if some_condition():
    > ...
    > #if some_condition(local_variable): # This condition should
    > be added # raise SomeException
    > ...


    Pretty much the same applies. If you can move the new condition to the
    start or end of the method, you can patch. To insert it in an arbitrary
    spot in the middle, forget it.

    > Is it possible to tell Python to run the original method without
    > stopping when an exception is raised? so I can catch them on a wrapper
    > method and apply my conditional there.


    No. Your request doesn't even make sense. What are you going to catch if
    no exception is raised? What do you expect the method to do if it doesn't
    stop? Consider:

    def original(self, x, y):
    z = x + y
    print z
    return "hello world"[z]


    Suppose you pass x=1, y={} so that x+y fails. What do you expect Python
    to do if you tell it not to stop at an exception? What will it print?
    What result should it return?



    --
    Steven
    Steven D'Aprano, Dec 19, 2012
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dave Brueck

    OT: There's a monkey on my keyboard,

    Dave Brueck, Jan 9, 2004, in forum: Python
    Replies:
    0
    Views:
    301
    Dave Brueck
    Jan 9, 2004
  2. Roedy Green

    firefox and Sea Monkey

    Roedy Green, Mar 27, 2008, in forum: Java
    Replies:
    1
    Views:
    393
  3. George Sakkis
    Replies:
    3
    Views:
    352
  4. Shugo Maeda

    A bug of the monkey patch for REXML

    Shugo Maeda, Nov 8, 2008, in forum: Ruby
    Replies:
    0
    Views:
    87
    Shugo Maeda
    Nov 8, 2008
  5. Alfredo Mesen

    Help with FasterCSV monkey patch

    Alfredo Mesen, Jan 21, 2009, in forum: Ruby
    Replies:
    3
    Views:
    94
    James Gray
    Jan 22, 2009
Loading...

Share This Page