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

Mark Bourne nntp.mbourne at spamgourmet.com
Wed Aug 31 14:43:09 EDT 2022


Jach Feng wrote:
> Mark Bourne 在 2022年8月29日 星期一下午6:40:59 [UTC+8] 的信中寫道:
>> 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.
> When using dot notation to change variable, no matter if 'x.y' is a mutable or immutable object, the change
> will be seen in both modules except those early bindings.
> 
> --Jach

Yes, sorry, I'd used `x.y` as a way of referring to the variable `y` in 
module `x` as opposed to `y` in the current module.  It doesn't help 
that I added the second paragraph and didn't notice that the third was 
then out of context.

If you use `import x` and assign to `x.y`, that will as you say be seen 
in both modules.  On the other hand, if you use `from x import y`, then 
(as has been discussed) assigning to `y` in the module which has the 
import won't affect the value seen in module `x`.  However, if `y` is 
mutable (e.g. a list), and no new object is assigned to it, then `y` 
still points to the same object in both modules, so mutating that 
existing object (e.g. `y.append(123)`) *will* affect what's seen in both 
modules - they're both referencing the same object, and you've modified 
that object, as opposed to assigning a new object to `y` in one of the 
modules.

-- 
Mark.


More information about the Python-list mailing list