victor
victor

Reputation: 6768

Python import and module scoping (specifically sys.ps1)

Why does the following not work:

from sys import ps1
ps1 = 'something else '

but this does?

import sys
sys.ps1 = 'something else '

If I run the simple test

import sys
from sys import ps1
ps1 = 'something else'
sys.ps1 = 'something else'

the first assignment doesn't work, but the second does. the id() for both ps1 and sys.ps1 are the same, so they should refer to the same thing, right?

Upvotes: 2

Views: 622

Answers (2)

jarmod
jarmod

Reputation: 78823

The amount of confusion that Python's import statement causes should keep its inventors up at night!

Here is a page that attempts to explain import. In particular it describes:

  • import X imports the module X and you use X.name to refer to name defined in module X

  • from X import * imports the module X but creates references in the current namespace to all public objects defined in X. You use name to refer to name that's defined in X, but X itself is not defined, so X.name does not work.

One way, perhaps, to look at from X import * is almost as if it inserts the entire source of module X inline and hence you simply use name directly as if it were inline and you cannot use X because it no longer exists.

Note that the practice of importing * from a module or package is frowned upon.

Upvotes: 0

abarnert
abarnert

Reputation: 365925

The short version is: Assignment doesn't mutate anything in Python, it just rebinds names. Rebinding a different name, that happens to be currently bound to a reference to the same string as sys.ps1 doesn't affect sys.ps1 in any way.

Let's go through step by step:

from sys import ps1

This imports sys (but doesn't bind a name sys in the current globals), then binds the name ps1 in the current globals to the same object as sys's ps1.

ps1 = 'something else '

This rebinds the name ps1 in the current globals to the same object as the literal 'something else'. There's no way that could possibly affect the sys module.

import sys

This imports sys, and then binds the name sys in the current globals to it.

sys.ps1 = 'something else '

This looks up the name sys in the current globals, getting a reference to the sys module, then rebinds the name ps1 in that module to the same object as the literal 'something else '.


Or, putting it in pseudo-Python terms, instead of in English…

Your first code sample is like this:

tempspace._sys = __import__('sys')
globals.ps1 = tempspace._sys.ps1
del tempspace._sys
globals.ps1 = 'something else '

Your second is like this:

globals.sys = sys_modules.sys = __import__('sys')
globals.sys.ps1 = 'something else '

Here is a transcript of what you described in the comments.

Python 2.7.2 (default, Jun 20 2012, 16:23:33) 
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> from sys import ps1
>>> id(sys.ps1)
4360831168
>>> id(ps1)
4360831168
>>> sys.ps1 = 'something else '
something else ps1
'>>> '
something else 

sys.ps1 and ps1 have the same ID, because they are two different names that reference the same object.

And changing sys.ps1 does not change ps1.

Upvotes: 3

Related Questions