0

I have the following problem.

My program will heavily work with plugins, which will perform computationally demanding tasks. But in different runs of the program the required operations (performed by plugins) may be the same. In order to speed things up (among other reasons), I would like to detect that the user gave the program the same plugin. Plugin is just a callable in my case.

The question is - how can I detect it?

Of course, code equivalence is absolute necessity for this kind of check, as was pointed out in (*). But obviously, it is not sufficient (**).

Because I will pass the arguments by their names (i.e. by dict unpacking), it surely needs to be checked that the the same arguments play the same role in the function.

Simalarly, something clearly must be forbidden. For example to load some data from a file and produce the output out of them (then any meaningful check is undoable).

Ideally, I would like to achieve similar mechanism that works well in functional languages, that is the output of a function is fully determined by values its arguments. Then if the function recieves the same set of arguments, its output can be just loaded (in one run of the program, though). Such mechanism relies of the fact that these functions are stateless.

To state my question more clearly - what kinds of restrictions (not necessarily checkable - they can be only documented) do I need to put on functions that come to me to be able to check that two of them are the same? (For example use only local variables, no closures etc.) Also, how these restrictions look like in practise.

My question comes from the fact that I know little about how the functions are represented in Python, so if anyone know a comprehensive text or video about this issue, it would help also.

Thank you.

(*) Check if two Python functions are equal

(**) https://gist.github.com/sharth/7536465

Tomáš Hons
  • 355
  • 3
  • 11
  • 1
    Basically, you can't. – jonrsharpe Aug 21 '20 at 20:28
  • If you only want to check if the code is equivalent, what more do you need to do? Code equivalence implies that the arguments are the same. – Barmar Aug 21 '20 at 20:28
  • 2
    Cant you just identify the plugin? I assume you know that callable? Then you can simply state that your plugin functions should be without side-effects because you are caching the results. Obv you need to trust the implementers that they don't actually reply on them. Or have them specify whether side-effects are possible, and not cache in those cases. – adjan Aug 21 '20 at 20:30
  • @jonrsharpe Say, the method has as its data only local variables and arguments and calls only other stateless functions (e.g. range and all these basic stuff). Then code equivalence is enough.. so I can. But these requirements may be too harsh (at least some closure of global variable would be nice, if the plugin is sole method in module) so I want to explore if anything less restrictive is possible. – Tomáš Hons Aug 21 '20 at 20:45
  • @Barmar I don't think that it is sufficient to check that the code is equivalent, if I pass their arguments via dict unpacking as mentioned. For example def f(a,b): return a; def g(b,a): return b; and run it with dict d = {'a': 1, 'b': 2}. Codes are the same, outputs are different despite this functions are the simplest imaginable. – Tomáš Hons Aug 21 '20 at 20:55
  • They're not the same functions, because if you call them with positional arguments they do different things. – Barmar Aug 21 '20 at 20:57
  • But you misunderstood me. I said they have the same code they're the same function. It's possible to be equivalent with different code. Solving that requires solving the halting problem. – Barmar Aug 21 '20 at 20:58
  • @Adrian Yes, problem is about plugin identification. Plugins will be determined by name (and version probably), but you know how people work. They will run the program, realize that their plugin is wrong. So they'll start modify the code without proper declaration (ie change of version). Once it will actually produce a result, which will be stored, they'll realize that the plugin is still wrong but know the database of result is spoiled. Nevertheless, they will modify their code further, but it will not actually run as the result is just loaded. I want to prevent this bad workflow by checking. – Tomáš Hons Aug 21 '20 at 21:07
  • @Barmar I assumed that by code equivalence you mean the equivalence in __code__.co_code attribute. In this sense, they are the same. The way I intend to call them, they do different things. On the other hand, they work exactly same being called with positional arguments. – Tomáš Hons Aug 21 '20 at 21:15
  • @Barmar Also, I am aware that in full generality, it is impossible to check functions equivalence. Hence, I seek a set of requirements to put on these functions to be able to do the check. Code equivalence is just the first step. – Tomáš Hons Aug 21 '20 at 21:17
  • Doesn't the `code.co_code` attribute include the code that gets arguments that are supplied by name? If the correspondence between names and argument positions is elsewhere, you'll need to include that in your comparison (unless the parameter list has the option that prohibits using named arguments). – Barmar Aug 21 '20 at 21:35

0 Answers0