That's because the compiler doesn't know the locals() dictionary will be modified at runtime, so it treats b as a global variable (which happens to be undefined).
To show that not even changes to existing local variables work, try
def main():
a = 1
d = locals()
print d
b = None
d['b'] = 123
print b
print d
print locals()
print d is locals()
To show that not even changes to existing local variables work, try
which prints I.e. changes to the dictionary returned by locals() are ignored, and calling locals() again overrides the previous values.