开发者

Unexpected import behavior, treating integers and lists differently

I have a problem with my program and I was able to reproduce this unexpected (at least unexpected to me) behavior in a small scale so now I'm certain it is not another bug.

Lets say I have 3 python modules: one, two and three.

In three we have:

var = 0
list = []

So there we have a integer that is equal to zero and and empty list.

In two we have:

from three import var, list

def funct():
    print var*2
    print list
    return

So we import var and list and simply define a function that will print both and return.

Instead of calling funct() in two I called it in one, but not before doing some "operations" to them.

from three import var, list
from two import funct

if 2 < 4:
    var += 1
    list.append("x")

print funct(开发者_JAVA百科)

So here comes my question.

I never expected this result:

0
['x']
None

How come the x was added to the list with the append() and 1 was NOT added to var, to be clear. I was expecting:

2
['x']
None

If find it very strange that they receive different treatments under the same circumstances.

  • Am I missing something here?
  • Am I doing something wrong with the imports?

If not:

  • Why does it behave like this?
  • How should this problem be solved / approached?

Thank in advance.


To "fix" your program, you would have to add "global var", as in:

if 2 < 4:
     global var
     var += 1
     list.append("x")

But this is illegal according to http://docs.python.org/reference/simple_stmts.html#global:

Names listed in a global statement must not be defined as formal parameters or in a for loop control target, class definition, function definition, or import statement.

Then again, following the link above:

CPython implementation detail: The current implementation does not enforce the latter two restrictions, but programs should not abuse this freedom, as future implementations may enforce them or silently change the meaning of the program.

Edit:

The solution is to change:

from three import var, list

to:

from three import list
import three

then don't use global namespace, but specify explicitly the namespace of three (you imported the symbol)

code:

three.var += 1

Make sure two.py and one.py are changed accordingly in their import/from statements

http://docs.python.org/tutorial/modules.html#more-on-modules

Each module has its own private symbol table, which is used as the global symbol table by all functions defined in the module. Thus, the author of a module can use global variables in the module without worrying about accidental clashes with a user’s global variables. On the other hand, if you know what you are doing you can touch a module’s global variables with the same notation used to refer to its functions, modname.itemname.


This is nothing to do with import, and everything to do with the different types involved.

list is a mutable type. list.append modifies the object in place, and returns None.

int is an immutable type. Its += operator returns a new object.

Learn more about mutable and immutable types at the Python documentation of its data model.


Importing a name copies the reference the name contains to your module. In your code, the integer gets rebound, but the list gets mutated. Since the list reference never changes, the original object is mutated. Hence different integer, same list.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜