2

I would like to be able to inject a piece of code in the beginning of a given function.

Research mostly mentions using decorators, but for my specific use case I wouldn't want to wrap the modified function with an additional function call.

I am also unable to add a parameter to the function - I have an already compiled function at runtime and that's it.

The reason I wouldn't want to use a wrapper, is because I'd like to write a utility library which allows the programmer to "paste" a piece of code at the beginning of an already written function, without adding another level to the call stack at all. Mainly for performance reasons.

How can this be done? And would it work across Python versions without breaking?

Aviv Cohn
  • 15,543
  • 25
  • 68
  • 131
  • You could try to pass the code that you want to run as a function and just call that. E.g https://stackoverflow.com/questions/706721/how-do-i-pass-a-method-as-a-parameter-in-python – Syrius Feb 04 '19 at 15:48
  • You can't really unless you take the source code apart and reassemble it. The smallest unit of code you have access to using regular Python is a function, not individual lines. So a wrapper is the most common way to do what you want. Why doesn't that work for you? – deceze Feb 04 '19 at 15:52
  • Can you elaborate on why you don't want to add an additional function call? Do you have performance concerns? There are probably very hacky - and not very pythonic - workarounds based on `inspect.getsource`, but I would definitely try anything else before going that way. – Giorgio Balestrieri Feb 04 '19 at 15:52
  • @GiorgioBalestrieri Thanks for taking your time to comment :) I added clarification to the main question. – Aviv Cohn Feb 04 '19 at 16:01
  • Would it be that difficult to test whether the decorator approach would actually have a significant performance impact on your solution? – cody Feb 04 '19 at 16:03
  • @cody Generally I absolutely agree with the state of mind of following the path of most clarity and caring about performance last. In this specific case, I would like to simply assume it will have a major performance impact. That's because the lib I'd like to write is supposed to be applied to many functions in one's application. – Aviv Cohn Feb 04 '19 at 16:07
  • Any solution will involve you decompiling and recompiling the function at runtime, you need to be sure that doesn't have a bigger impact on your performance than the decorator – yorodm Feb 04 '19 at 16:14
  • You want to effectively change the python interpreter. You could dynamically create new function objects by playing with byte code. As a user of the library I would be quite confused. I would not see the injected code, nor be able to debug it. – Mihai Andrei Feb 04 '19 at 16:15
  • You can mess with the bytecode of the function and the block that should be inserted. There are modules to analyze/decompile/assemble CPython's bytecode. Also take a look at [this](https://rushter.com/blog/python-bytecode-patch/). – ForceBru Feb 04 '19 at 16:17
  • @yordom it will happen only once, and not on any call to the function – Aviv Cohn Feb 04 '19 at 16:24
  • @ForceBru Are these techniques prone to breaking between minor Python versions? – Aviv Cohn Feb 04 '19 at 16:40
  • @AvivCohn, probably not, but that's not a terribly reliable method anyways since the bytecode may be changed whenever the devs want it – ForceBru Feb 04 '19 at 16:41

1 Answers1

1

Premature optimization is the root of all evil. You should not "simply assume" a wrapper function will have a major performance impact. There is no safe, simple, portable, way to do what you're asking. The most applicable solution is a custom metaclass as it allows you to control the creation of new objects based on it.

Kurtis Rader
  • 6,734
  • 13
  • 20