Imagine there is a restaurant with many tables and seats. You and your family go in the restaurant. The mute receptionist sees that you have 5 people, and leads you to a table G, with 5 seats. Now table G is occupied by your family. When you are done eating, you leave the restaurant. The receptionist sees that and table G is unoccupied. The next family of 5 that comes are able to use table G. This whole time, you did not speak to the receptionist at all, because he is mute.
Now Imagine there is another restaurant with many tables and seats. You and your family go in the restaurant. The blind receptionist asks "how many people"? and you tell him 5. The blind receptionist finds an unoccupied table E with enough seats for 5 people. He's blind so he doesn't want to talk and trip, so he tells you where the table is. Now table E is occupied by your family. When you are done eating, you leave the restaurant. However, you forgot to tell the blind receptionist that you left. He still thinks table E is occupied by you, so table E will not be given to any customers.
tables and seats = memory, since they are space.
customers = data, since they are the contents that occupy space.
the act of entering/leaving restaurant = entering and leaving a scope.
the act of being led to a table by the mute receptionist = automatic allocation.
the act of telling the blind receptionist how many seats you need at the minimum, and getting the location of the seats/tables = dynamic allocation.
This analogy omits some details, but I hope that helps.
Whatever you do, you are probably reinventing the wheel. I don't think there's anything wrong with it though. If you have a problem and you come up with a system to solve it, good for you, and you learned something, wheel or not.
Why isn't it guaranteed the prints will run? I know some people say some prints might break during certain situations but I don't really understand why. If the if statement is true, then the program has to run the print before it can return right?
The print function run, it's just that they might not actually print to the screen until you flush the buffer or the buffer gets full.
Another way is to perform your collision solving step multiple times per frame, because solving collision once could lead to new collisions. So think of it as a fixed point method, refining your physics world the more times you run it.
Since it's a hardware limitation, one way to go around that problem is to allow the player to customize key bindings. That way, if my keyboard can't accept key A and key B at the same time, I'll just change the keys until I'm satisfied with it.