Python basics: interactive script
You have basically 2 options: modal operator or scene update handler.

Modal operator is what an interactive script would use, here is an example with over-commented code. It will create panel in tools under Misc. and the operator can be ended with ESC:

import bpy
# for random positioning of cubes
# so they dont stack one over other
from random import random

class Panel(bpy.types.Panel):
    """
    This displays number_of_cubes property in tools panel
    And can run a modal operator
    """
    bl_label = "Custom Panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'

    def draw(self, context):
        # display cube count if modal operator running 
        # else display button to run it
        layout = self.layout
        if context.scene.watcher_running:
            layout.prop(context.scene, "number_of_cubes")
        else:
            layout.operator("my_custom_op.cube_watcher")

class CubeWatcher(bpy.types.Operator):
    """This will run in background monitoring user actions"""
    bl_idname = "my_custom_op.cube_watcher"
    bl_label = "Cube Watcher"

    # this function should be used to do stuff
    # in our example to adjust the number of cubes
    def execute(self, context):

        # get cubes already present in scene
        cube_list = [object for object in context.scene.objects if object.name.find("Cube") &gt;= 0]

        if len(cube_list) &lt; context.scene.number_of_cubes:
            # add cubes
            for i in range(context.scene.number_of_cubes - len(cube_list)):
                bpy.ops.mesh.primitive_cube_add(enter_editmode=False)
                context.active_object.location = (5-10*random(), 5-10*random(), 5-10*random())

        elif len(cube_list) &gt; context.scene.number_of_cubes:
            # remove excess cubes
            for i in range(context.scene.number_of_cubes, len(cube_list)):
                context.scene.objects.unlink(cube_list[i])
        return

    # this function will be called everytime user does something, even moves a mouse
    # should be used to react to user input
    def modal(self, context, event):

        # when user interacts, adjust number of cubes
        # this will react to all event types
        # which is kinda inneficient but simple
        self.execute(context)

        # end modal operator when hitting ESC
        if event.type == 'ESC':
            # set the monitoring property to False
            context.scene.watcher_running = False
            return {'FINISHED'}

        # all other events pass through to blender
        return {'PASS_THROUGH'}

    # this is run when this operator is called
    # usually inicialization code is here
    def invoke(self, context, event):

        # this is important, it will run the modal function
        # without this the operator would just execute and end
        context.window_manager.modal_handler_add(self)

        # set the monitoring property to True
        context.scene.watcher_running = True

        # run self to spawn cubes
        self.execute(context)

        return {'RUNNING_MODAL'}

def register():
    # register classes so blender knows about them
    bpy.utils.register_module(__name__)
    # add a property to scene that will control number of cubes
    bpy.types.Scene.number_of_cubes = bpy.props.IntProperty(default=0, min=0)
    # add a property that will monitor if modal operator is running or not
    bpy.types.Scene.watcher_running = bpy.props.BoolProperty(default=False)

def unregister():
    # unregister classes
    bpy.utils.unregister_module(__name__)
    # remove properties
    del bpy.types.Scene.number_of_cubes
    del bpy.types.Scene.watcher_running

if __name__ == "__main__":
    register()


A handler is a function added to some event, in this case before scene updates. This will produce similar result as code before but will be much more likely buggy or laggy. Next example is simple and does not handle any error cases. Use this only when you know what you are doing.

import bpy
from random import random

def cube_count_handler(scene):
    """This function will be run everytime before scene updates"""
    cube_list = [object for object in scene.objects if object.name.find("Cube") &gt;= 0]
    if len(cube_list) &lt; scene.number_of_cubes:
        for i in range(scene.number_of_cubes - len(cube_list)):
            loc = (5-10*random(), 5-10*random(), 5-10*random())
            bpy.ops.mesh.primitive_cube_add(enter_editmode=False, location=loc)

    elif len(cube_list) &gt; scene.number_of_cubes:
        for i in range(scene.number_of_cubes, len(cube_list)):
            scene.objects.unlink(cube_list[i])
    return

class PropPanel(bpy.types.Panel):
    bl_label = "Custom Panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'

    def draw(self, context):
        layout = self.layout
        layout.prop(context.scene, "number_of_cubes")

def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.number_of_cubes = bpy.props.IntProperty(default=0, min=0)
    # add handler if not in app.handlers
    if cube_count_handler not in bpy.app.handlers.scene_update_pre:
        bpy.app.handlers.scene_update_pre.append(cube_count_handler)

def unregister():
    bpy.utils.unregister_module(__name__)
    del bpy.types.Scene.number_of_cubes

if __name__ == "__main__":
    register()