Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #35044 > unrolled thread
| Started by | Marc Aymerich <glicerinu@gmail.com> |
|---|---|
| First post | 2012-12-18 02:26 -0800 |
| Last post | 2012-12-19 00:54 +0000 |
| Articles | 5 — 5 participants |
Back to article view | Back to comp.lang.python
Is it possible monkey patch like this? Marc Aymerich <glicerinu@gmail.com> - 2012-12-18 02:26 -0800
Re: Is it possible monkey patch like this? Chris Angelico <rosuav@gmail.com> - 2012-12-18 21:34 +1100
Re: Is it possible monkey patch like this? Peter Otten <__peter__@web.de> - 2012-12-18 13:35 +0100
Re: Is it possible monkey patch like this? Terry Reedy <tjreedy@udel.edu> - 2012-12-18 11:49 -0500
Re: Is it possible monkey patch like this? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-12-19 00:54 +0000
| From | Marc Aymerich <glicerinu@gmail.com> |
|---|---|
| Date | 2012-12-18 02:26 -0800 |
| Subject | Is it possible monkey patch like this? |
| Message-ID | <bbfb8154-e283-4961-9680-9d819bf00d01@googlegroups.com> |
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!
[toc] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2012-12-18 21:34 +1100 |
| Message-ID | <mailman.1014.1355828213.29569.python-list@python.org> |
| In reply to | #35044 |
On Tue, Dec 18, 2012 at 9:26 PM, Marc Aymerich <glicerinu@gmail.com> 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
[toc] | [prev] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2012-12-18 13:35 +0100 |
| Message-ID | <mailman.1017.1355834069.29569.python-list@python.org> |
| In reply to | #35044 |
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...
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2012-12-18 11:49 -0500 |
| Message-ID | <mailman.1023.1355849362.29569.python-list@python.org> |
| In reply to | #35044 |
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
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2012-12-19 00:54 +0000 |
| Message-ID | <50d11034$0$29991$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #35044 |
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
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web