2

Lets say I have a python program that is a black box and that acts like a processor. It reads a text file with some instruction names, parses this file and calls the functions from a class Instructions. What I want is to allow the user to create new functions in another file, and allow the processor to call these functions via the Instructions class.

Example processor code (cannot change this):

from instructions import *

instr = Instructions()
code = []
with open('program.txt') as f:
    code = f.readlines()

for line in code:
    command, args = line.split()
    # reads "command arg" and calls "instr.command(arg)"
    string_exec = 'instr.{}({})'.format(command, args)
    eval(string_exec)

Example instructions.py:

class Instructions:
    def show(self, arg):
        print(arg, end='')

Example of 'program.txt' that the processor reads to print "Hello":

show 'H'
show 'e'
show 'l'
show 'l'
show 'o'
show '\n'

I want to be able to read a file from the user with new instructions and be able to execute them in the processor.

Example of user function that also uses the instructions:

def print_line(self, args):
    for arg in args:
        instr.show(arg)
    instr.show('\n')

I want to incorporate the user functions into the class Intructions somehow, such that the processor can be able to run the following 'program.txt':

print_line 'Hello'

In short, I want to divide the Instructions functions in two files, one with some basic 'fixed' instructions, and the other with 'dynamic' functions the user defines. At the end I want to load both functions in the class Instructions.

klaus
  • 1,187
  • 2
  • 9
  • 19
  • 1
    Have you tried [inheritance](https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming))? – chrisaycock Aug 22 '18 at 02:20
  • The processor code imports only the class Instructions. If the user functions are an inherited class from Instructions, I would still need to load this new class into the instructions file. – klaus Aug 22 '18 at 02:28
  • You can add methods to an existing class or class instance, but it gets ugly. Check [Adding a Method to an Existing Object Instance](https://stackoverflow.com/questions/972/adding-a-method-to-an-existing-object-instance) – John Anderson Aug 22 '18 at 02:38
  • Can you think of easier ways other than adding new methods to the Instruction class? – klaus Aug 22 '18 at 02:42

1 Answers1

2

instructions.py like this:

class Instructions:
    def __init__(self):
        self._add_user_function()

    def add(self, a, b):
        return a + b

    def _add_user_function(self):
        import os
        if not os.path.exists('user_instructions.py'):
            return
        from user_instructions import UserInstructions
        self._user_instrucs = UserInstructions(self)
        for prop in dir(self._user_instrucs):
            if prop.startswith('_'):
                continue
            prop_type = type(eval("UserInstructions.%s" % prop))
            if str(prop_type).find("instancemethod") < 0:
                continue
            func_str = "def instr_custom_%s(self, *args, **kwargs):\n    return self._user_instrucs.%s(*args, **kwargs)\n    " % (prop, prop)
            exec(func_str)
            setattr(Instructions, prop, eval("instr_custom_%s" % prop))

    def show(self, arg):
        print(arg)

user_instructions.py like below:

class UserInstructions:

    def __init__(self, instr):
        self.__instr = instr

    def print_line(self, args):
        print(args)
zhiwen
  • 82
  • 4
  • I can't change the processor code, so this does not solve the problem. – klaus Aug 22 '18 at 02:47
  • I can change the instructions code, but it still has to be able to be executed by the processor. – klaus Aug 22 '18 at 02:59
  • Thus you put print_line method in class Instructions, that will take effect. – zhiwen Aug 22 '18 at 03:02
  • print_line is just one function that the user might create. The user should be able to create any function he wants in another file and it should be added to the other instructions of the class Instructions. – klaus Aug 22 '18 at 03:25
  • Then I think you should just define another input python file, and you can parse the file and added function to Instructions class. Like you should implement a function like add_custom_function in Instructions, this method will parse your defined file and added functions to Instructions, and in program.txt you should run this add_custom_function first. – zhiwen Aug 22 '18 at 03:30
  • How can I do that? Maybe you should update your answer. – klaus Aug 22 '18 at 03:36
  • 1
    @klaus Just... define the function and snap it to the class like you're changing one of it's attributes. It's as straightforward as it gets. – Havenard Aug 22 '18 at 03:39
  • I updated the answer. And in UserInstructions variable defined should starts with _, exported function should not starts with _ – zhiwen Aug 22 '18 at 05:10
  • I ended up solving by changing your solution a little, but the idea is the same. Thanks – klaus Aug 23 '18 at 01:05