Script calculated multiple times on frame
Clean the handlers.
with no handlers appended at all, running question script will print the frame once.
There is only one function assigned
&gt;&gt;&gt; for f in bpy.app.handlers.frame_change_pre:
...     f.__name__, f.__module__
...     
('tester', '__main__')

running question script three more times
&gt;&gt;&gt; for f in bpy.app.handlers.frame_change_pre:
...     f.__name__, f.__module__
...     
('tester', '__main__')
('tester', '__main__')
('tester', '__main__')
('tester', '__main__')

will see frame printed 4 times. (One assumes you made an edit to get the -1)
Clear the handler.
Can clear all the functions assigned to a hander via
bpy.app.handlers.frame_change_pre.clear()  

to remove all the methods from each time you run script above.
Or iterate over appended funcions and remove those where f.__name__ == &quot;tester&quot; or by module if testing in text editor (__name__ == &quot;__main__&quot;)
When a handler is assigned a method via an addon, it can be appended in the register and removed in the unregister.  The namespace of the addon ensures its the same method both times  my_addon.foo_function  whereas when run from main thread &quot;__main__.foo_function&quot; is not seen as the same.
Example in console of removing any frame change pre handler function added via main thread.
&gt;&gt;&gt; fs2remove = [f for f in bpy.app.handlers.frame_change_pre
...     if f.__module__ == &quot;__main__&quot;]

&gt;&gt;&gt; fs2remove
[&lt;function tester at 0x7ffac5165ca0&gt;, &lt;function tester at 0x7ffac51659d0&gt;, &lt;function tester at 0x7ffac5165d30&gt;, &lt;function tester at 0x7ffac5165550&gt;, &lt;function tester at 0x7ffac5165700&gt;]
&gt;&gt;&gt; while fs2remove:
...     bpy.app.handlers.frame_change_pre.remove(fs2remove.pop())
...     
&gt;&gt;&gt; bpy.app.handlers.frame_change_pre[:]
[]