Python hot swap code (duck type functions?)

I have been thinking about this for too long and had no idea, perhaps some of you may be able to help.

I have a python script folder, all of which have the same environment (literally, I generated it from a shell script), but have one piece that is different from everyone. In other words:

Top piece of code (always the same) Middle piece of code (changes from file to file) Bottom piece of code (always the same) 

And today I realized that this is a bad idea, for example, if I want to change something from the top or bottom, I need to write a shell script to do this. (Not that it is complicated, it just seems very bad code wise).

So what I want to do is there is one external python script that looks like this:

 Top piece of code Dynamic function that calls the middle piece of code (based on a parameter) Bottom piece of code 

And then every other python file in the folder may just be the middle part of the code. However, the normal module will not work here (if I'm not mistaken), because I will get the code that I need to execute from the argument, which will be a string, and therefore, I don’t know which function will work until runtime.

So, I came up with two more solutions:

  • I could write a bunch of if statements, one to run each script based on a specific parameter. I rejected this as it is even worse than the previous project.
  • I could use:

    os.command (sys.argv [0] scriptName.py)

    which will run the script, but calling python to call python doesn't seem very elegant to me.

Does anyone have any other ideas? Thanks.

+4
source share
6 answers

If you know the function name as a string and the module name as a string, you can do

 mod = __import__(module_name) fn = getattr(mod, fn_name) fn() 
+4
source

Another possible solution is for each of your duplicate files to import functionality from the main file

 from topAndBottom import top, bottom top() # do middle stuff bottom() 
+4
source

In addition to the few answers already posted, consider a template template : create an abstract class like

 class Base(object): def top(self): ... def bottom(self): ... def middle(self): raise NotImplementedError def doit(self): self.top() self.middle() self.bottom() 

Each plug-in then creates a class that inherits from this Base and must override middle with the corresponding code.

Perhaps this is not justified for this simple case (you still have to import the correct module to create an instance of the class and call doit on it), but you should still keep in mind (along with its many variations of Pythonic, which I explain in detail in many technological negotiations, which are now available on youtube) for cases when the number or complexity of “plug-in elements” continues to grow - the Template Method (despite its terrible name ;-) is a robust, well-established and scalable template [[sometimes too tedious, but exactly what I mention in those numerous technology negotiations, and this problem does not apply to this particular use case]].

+2
source

However, the normal module will not work here (if I’m not mistaken), because I will get the code that I need to execute from the argument, which will be a string, and therefore, I don’t know which function runs before execution.

It will work just fine: __import__ built-in or, if you have a very complex layout, imp to import the script. And then you can get the function module.__dict__[funcname] , for example.

0
source

Importing a module (as explained in other answers) is certainly a cleaner way to do this, but if for some reason this doesn't work, if you don't do anything too weird, you can use exec . It basically runs the contents of another file, as if it were included in the current file at the point where exec is called. This is the closest Python element to a source expression of the type included in many shells. At a minimum, something like this should work:

 exec(open(filename).read(None)) 
0
source

How about this?

 function do_thing_one(): pass function do_thing_two(): pass dispatch = { "one" : do_thing_one, "two" : do_thing_two, } # do something to get your string from the command line (optparse, argv, whatever) # and put it in variable "mystring" # do top thing f = dispatch[mystring] f() # do bottom thing 
0
source

All Articles