BGE : AddObject adding two object 8 years using blender and still, never tried the Python API. Never too late to begin! Then I was stuck on something very frustrating, tried 2 days, created variant, searched for bugtracks and looking for others stack thread. 

The context

I'm working on a "civ-like" game with tiles. To generate my map I want to run a small "buildmap.py" script allowing to place tiles and control them.

So, I put the tiles and tiles variant on my second layer and call them from the first layer with a "spawner" Empty object at the launch of the scene:

Always (tap) -> python : buildmap.py 

Here is the code :

import bge

world = bge.logic.getCurrentScene()

world.addObject("Tile", "spawner",0)


The problem

When I launch the game everything looks good, the tiles are placed at the right places. Then I clicked on the first one... And realized that my script putted 2 "Tile" objects on each position. I removed the loop to study the addObject and branch it to a keyboard with same result.
By calling once addObject it places 2 objects.

Maybe I’m missing something ? so I came here :)
Do not enable the [Tap] option. It makes no sense.

Background

The Always sensor "always evaluates positive".

Any sensor will trigger all connected controllers when the evaluation result changes (from not positive to positive and from positive to not positive).

As the always sensor never evaluate not positive, it will only trigger when the object was just created. So it is more a "is created" trigger.

There are configuration options that modify the behavior of the sensor. You set the Tap option. This option changes the behavior of the sensor to evaluate not positive the next frame after evaluating positive, regardless of the real situation. This was introduced to make the use of the keyboard sensor a bit more comfortable.

As you enabled that option, you get this processing from the always sensor


frame 1: evaluate positive -> (result changed): trigger the controller 
frame 2: evaluate negative (because of Tap) -> (result changed): trigger the controller
frame 3+: evaluate negative -> no trigger


Solutions

Assumption: single trigger

With the default settings (no Tap, no Triggering Levels, no Inv ...) the always sensor (and the delay sensor) will trigger the controller exactly once.

With that Assumption (one trigger) you can run your Python code as is.

Common use case

When you have different settings or other sensors (like a keyboard sensor) you need to implement the supposed behavior of a controller. 

You ALWAYS check the status of ALL connected sensors and consider that in your custom code.

if all(sensor.positive for sensor in bge.logic.getCurrentController().sensors):
    ...
else:
    ...


Remark: even the basic controllers (AND, OR ...) do that. That is the minimum code you should write (unless the above assumption applies).