Any assignment to a name in a function makes the name local to the function. It doesn't matter where in the function the assignment is, even if it's the last statement in the function: the name is local to the function. If you use a local name before it's been assigned to, you get the error you see.
It doesn't matter that the name is also available in the global scope. The compiler knows that the name is local, and will only look for it in the local scope.
An import statement is a form of assignment. Your "import json" statement in the function makes the name "json" local to the function. You are using the name before it's been imported locally, so you are using an unbound local.
The "global" statement means, even though this name is used in an assignment statement, it's not a local name, it's a global name. In your second function, the global statement makes the name "json" refer to the global "json", which is already defined when you try to access it, so your function works.