How to make a variable's late binding crosses the module boundary?

Mark Bourne nntp.mbourne at spamgourmet.com
Mon Aug 29 06:40:33 EDT 2022


Jach Feng wrote:
> Chris Angelico 在 2022年8月29日 星期一下午1:58:58 [UTC+8] 的信中寫道:
>> On Mon, 29 Aug 2022 at 15:54, Jach Feng <jf... at ms4.hinet.net> wrote:
>>>
>>> Richard Damon 在 2022年8月29日 星期一上午10:47:08 [UTC+8] 的信中寫道:
>>>> On 8/27/22 7:42 AM, Mark Bourne wrote:
>>>>> Jach Feng wrote:
>>>>>> I have two files: test.py and test2.py
>>>>>> --test.py--
>>>>>> x = 2
>>>>>> def foo():
>>>>>> print(x)
>>>>>> foo()
>>>>>>
>>>>>> x = 3
>>>>>> foo()
>>>>>>
>>>>>> --test2.py--
>>>>>> from test import *
>>>>>> x = 4
>>>>>> foo()
>>>>>>
>>>>>> -----
>>>>>> Run test.py under Winows8.1, I get the expected result:
>>>>>> e:\MyDocument>py test.py
>>>>>> 2
>>>>>> 3
>>>>>>
>>>>>> But when run test2.py, the result is not my expected 2,3,4:-(
>>>>>> e:\MyDocument>py test2.py
>>>>>> 2
>>>>>> 3
>>>>>> 3
>>>>>>
>>>>>> What to do?
>>>>>
>>>>> `from test import *` does not link the names in `test2` to those in
>>>>> `test`. It just binds objects bound to names in `test` to the same
>>>>> names in `test2`. A bit like doing:
>>>>>
>>>>> import test
>>>>> x = test.x
>>>>> foo = test.foo
>>>>> del test
>>>>>
>>>>> Subsequently assigning a different object to `x` in one module does
>>>>> not affect the object assigned to `x` in the other module. So `x = 4`
>>>>> in `test2.py` does not affect the object assigned to `x` in `test.py`
>>>>> - that's still `3`. If you want to do that, you need to import `test`
>>>>> and assign to `test.x`, for example:
>>>>>
>>>>> import test
>>>>> test.x = 4
>>>>> test.foo()
>>>>>
>>>> Yes, fundamental issue is that the statement
>>>>
>>>> from x import y
>>>>
>>>> makes a binding in this module to the object CURRECTLY bound to x.y to
>>>> the name y, but if x.y gets rebound, this module does not track the changes.
>>>>
>>>> You can mutate the object x.y and see the changes, but not rebind it.
>>>>
>>>> If you need to see rebindings, you can't use the "from x import y" form,
>>>> or at a minimum do it as:
>>>>
>>>>
>>>> import x
>>>>
>>>> from x import y
>>>>
>>>> then later to get rebindings to x.y do a
>>>>
>>>> y = x.y
>>>>
>>>> to rebind to the current x.y object.
>>>>
>>>> -- 
>>>> Richard Damon
>>> Yes, an extra "import x" will solve my problem too! Sometimes I am wondering why "from x import y" hides x? hum...can't figure out the reason:-)
>>>
>> "from x import y" doesn't hide x - it just grabs y. Python does what
>> you tell it to. :)
>>
>> ChrisA
> But I had heard people say that "from x import y" did import the whole x module into memory, just as "import x" did, not "grabs y" only. Is this correct?

`from x import y` does import the whole module x into memory, and adds 
it to `sys.modules`.  But it only binds the name `y` in the namespace of 
module doing the import (and it binds it to the value of `x.y` at the 
time the import is done - it doesn't magically keep them in sync if one 
or the other is later reassigned).

The point about the whole module being imported is that you don't save 
any memory by using `from x import y` to avoid importing some very large 
object `z` from `x`.  Those other large objects might be needed by 
functions which have been imported (e.g. your `foo` function still needs 
`x` even if you haven't imported `x` - so it still needs to be loaded 
into memory) or might be imported and used by other modules importing 
`x`, so they still have to be loaded when any part of `x` is imported - 
they just don't have to be bound to names in the importing module's 
namespace.

As Richard mentioned, if `x.y` is a mutable object (such as a list) you 
can still mutate that object (e.g. add/remove items) and those changes 
will be seen in both modules.  That's because both are still bound to 
the same object and you're mutating that existing object.  If you assign 
a new list to either, that won't be seen by the other.

-- 
Mark.


More information about the Python-list mailing list