I find it very useful to be able to create new variables during runtime and create a dictionary of the results for processing later, i.e. writing to a file:
From the help for vars,
vars(...) vars([object]) -> dictionary
Without arguments, equivalent to locals(). With an argument, equivalent to object.__dict__.
You are using it without vars, so let's look at the help for locals()
locals(...) locals() -> dictionary
Update and return a dictionary containing the current scope's local
variables.
So this answers you first two questions. vars() returns a dictionary to the local variables that is indexed by the name of the variable as a string. The scope is local.
I'm not sure about the third question, but it does seem like kind of a hack which isn't a good sign. I guess if you're careful about using this only in the correct scope you can get by with it.