1

This is a question about Sage, which is based on Python 2.7. I've written up the sage question here, but will modify that question to remove the mathematical context.

I'm trying to improve the speed of a few slow functions for very specific cases. Essentially, I have a function foo, such that foo(args) is traditionally quite slow, but but due to analysis I've done by hand, foo(args') can be easily computed via bar(args') (for special cases of args' that are easy to check in practice). I'd like to have a new version of foo such that:

  1. If args == args', (or args in A, where A is some data structure that contains all inputs bar is correct for) it just calls bar(args)
  2. Otherwise, it calls foo(args)

Now, if foo were just defined in my own code, this would be trivial to fix (by modifying the definition, or potentially a decorator).

My issue is that foo is in module1 (not my code). module2 imports foo as well, and I want this change to be visible to everything in module2 as well (essentially, I myself never call foo, so for the speedup to occur I need other functions to compute the specific case quicker).

I have my own code that imports module1 and module2. Is there a way I could modify foo (from within my own code) to handle this special case faster, so that when functions in module1 and module2 call it they'll get the speedup as well? This is only really useful if it's possible without modifying the source code of module1 and module2.

EDIT

In light of the answer below, are there ways to monkey-patch calls to PARI in Sage? The method I'm trying to monkey-patch is described by the profiler as {method '_nf_rnfeq' of 'sage.libs.cypari2.gen.gen' objects}. In light of this, I tried the following, which didn't work.

import sage.libs.cypari2.gen
orig_nf_rnfeq = sage.libs.cypari2.gen.gen._nf_rnfeq
def _nf_rnfeq(*args, **kwargs):
    print("Rnfeq works!")
    return orig_nf_rnfeq(*args, **kwargs)

sage.libs.cypari2.gen.gen._nf_rnfeq = _nf_rnfeq

This leads to the error TypeError: can't set attributes of built-in/extension type 'sage.libs.cypari2.gen.gen

Mark
  • 324
  • 3
  • 9

1 Answers1

1
import module1
origfoo = module1.foo

def myfoo(*args):
    if args in A:
        return bar(*args)
    return origfoo(*args)

module1.foo = myfoo

Any module that imports module1 after this point will pick up your modified version of the function. You might have a problem if module1 itself imports module2 before you have a chance to apply the patch.

jasonharper
  • 9,450
  • 2
  • 18
  • 42
  • Upon trying to implement this, I get the following error: `TypeError: can't set attributes of built-in/extension type 'sage.libs.cypari2.gen.gen'`. It seems related to the problem [here](https://stackoverflow.com/questions/192649/can-you-monkey-patch-methods-on-core-types-in-python), so I'll try looking into that. – Mark Nov 27 '17 at 02:58