2

I am feeling particularly thick today. Consider

mod1.py

count = 0

def foo ():
    global count
    count = count + 1

mod2.py

import mod1

from mod1 import foo, count

print("mod1.count = ", mod1.count)
print("count = ", count)

foo()

print("mod1.count = ", mod1.count)
print("count = ", count)

I assumed the import of count into mod2 effectively globalized it.

> python3 mod2.py
mod1.count =  0
count      =  0
mod1.count =  1
count      =  0

I've obviously got some fundamental misunderstanding. I assumed the import would essentially make mod1.count and count aliases, but that is not the case. I am guessing this has to to with using both 'import' and 'from-import'.

mks
  • 51
  • 3

3 Answers3

1

The difference between them is probably usability.

import module

lets you access a method from the module using the . operator. while

from module import something

lets you use something without referring to the module using . operator. You can also say that it lets you use something globally.

Using the from methode you will have imported something globally. That doesn't mean that something from the module has vanished. It's just making new instances of the methods. so when you import both the module and the instance of something, you can literally access something either way (with or without using the . operator).

touhidurrr
  • 318
  • 2
  • 11
  • But in his example, he's getting the variable in the module using the `.` operator, even though he used `from module import variable`. – Barmar Sep 06 '19 at 20:41
0

I think you've pretty much answered your own question. They are not aliases, but two distinct objects, presumably because they exist in different namespaces. You can verify this more simply by doing your imports then print(mod1.count is count). This would return True if they were aliases.

Simon Notley
  • 2,070
  • 3
  • 12
  • 18
0

This is due to the way Python handles the names of variables. In order to have some basis for the explanation, I extended your example with a list as a second imported variable:

mod1.py

count = 0
lst = [1, 2, 3]

def update_count():
    global count
    count = count + 1

def update_lst():
    lst.append(4)

test.py

import mod1

from mod1 import count, lst, update_count, update_lst

print("mod1.count = ", mod1.count)
print("count = ", count)
print("mod1.lst = ", mod1.lst)
print("lst = ", lst)

update_count()
update_lst()
print('\nAfter updates: \n')

print("mod1.count = ", mod1.count)
print("count = ", count)
print("mod1.lst = ", mod1.lst)
print("lst = ", lst)    

Output:

mod1.count =  0
count =  0
mod1.lst =  [1, 2, 3]
lst =  [1, 2, 3]

After updates: 

mod1.count =  1
count =  0
mod1.lst =  [1, 2, 3, 4]
lst =  [1, 2, 3, 4]

So, what happened?

When you import count and lst, these new names are created in the namespace of your script. The name count is another name for the integer object 0 already referred to by mod1.count, and the name lst is another name for the list already referred to by mod1.lst.

When we execute the updates, the list gets updated in the module, but it remains the same object: mod1.lst and lst still refer to the same object.

Things are different for mod1.count, as we make this name refer to a new object, the integer 1, in count = count + 1. Now, mod1.count refers to the integer object 1, while count in the main script still refers to the original 0 object.

So, that's all just normal Python names behaviour.

If you haven't read it yet, I recommend Ned Batchelder's classic Facts and myths about Python names and values that explains very well how names work in Python.

Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50