"import mod" defines mod, which didn't exist in your module before.
"from mod import val" defines val, which didn't exist in your module before.
Most languages have scopes. Things may exist in your scope, so you can access them. Or they may exist but in some other scope not visible to you where you currently are. Symbol tables track what is in a scope.
A variable is a name associated with a storage location. The location could be a stack, heap, register, or something way more abstract as long as it behaves as a "place" you can store a value into and read from.
When a variable is created, a name is defined and some storage is arranged for. But that name is also added to a scope. (If it weren't, it would have a name, but nobody could see it.)
There's no reason, once the variable has been added to one scope, that it can't be added to another scope. That is what "import" statements do in a lot of languages.
Python has apparently chosen a very different approach for imports, which is to create a new variable. This isn't necessarily wrong or right, it's just not something I had ever seen a language do before.
I was also very surprised Python does it this way. Normally I would expect "import" statements in a language to just rearrange the namespace and have no other effects at all. The author explains that it doesn't work that way:
> “from mod import val” means, import mod, and then do the assignment “val = mod.val”.
In other words, I would expect an import to alter a symbol table. I would not expect it to create a new variable and then perform an assignment.