[Tutor] seeking design pattern

Mats Wichmann mats at wichmann.us
Sun Aug 25 11:26:36 EDT 2019


On 8/25/19 7:14 AM, bob gailer wrote:
> On 8/24/2019 9:47 PM, Cameron Simpson wrote:
>>
>> Can you describe why you would want the original behaviour you describe?
>>
>> Bear in mind that most Python names can be rebound. So you can rebind
>> "print" to a function of your own choosing. Should a() also honour that?
>>
>> Try to provide something you want to do in the real world which would
>> benefit from this name behaviour.
> 
> Thanks for your reply. My associate and I are co-authoring a project. I
> am developing the main program; he is writing arduino drivers.
> 
> In the main program I have several functions (e.g. log()) that are
> called from main program code and from the arduino drivers.
> 
> to keep a clean separation of code his drivers are in a separate module
> that is imported by the main program. So we have a need to access some
> of the functions I've written from both my code and his, which reside in
> 2 different modules.
> 

This should give you no problems, Python is coded this way all the time.
If you want to have a function in another module access some data,
import the module, call the function with the data as arguments, and
code the function to accept such - that's the "pattern".


==== more explanation, fine to skip

A module is just a Module object wrapping a dictionary. You can make
one, outside of the import system, just to see:

>>> y = 56
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__':
None, '__annotations__': {}, '__builtins__': <module 'builtins'
(built-in)>, 'y': 56}
>>> from types import ModuleType
>>> spam = ModuleType('spam')
>>> spam
<module 'spam'>
>>> spam.__dict__
{'__name__': 'spam', '__doc__': None, '__package__': None, '__loader__':
None, '__spec__': None}

There's no sign of the name 'y' from the current module's namespace in
the namespace of the new module.  This is entirely intentional.


Importing is roughly:
* Check if module you asked for is already in the module cache (i.e.
alteady imported), if so just return the ref and put that in the current
module's globals
* else
* find the file for the module you asked to import and read it in
* create a new module object
* compile the code you read in
* exec the compiled object in the context of the dictionary of the new
object so that dictionary will be populated by the result of running the
module code
* stick the module object in the module cache
* return a reference to the object and put that in the current module's
globals

Notice there's no harm at all in multiple files in your project all
importing the same thing (unless you goof up and manage to make circular
dependencies with your imports)


>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__':
None, '__annotations__': {}, '__builtins__': <module 'builtins'
(built-in)>, 'ModuleType': <class 'module'>}
>>> import spam
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__':
None, '__annotations__': {}, '__builtins__': <module 'builtins'
(built-in)>, 'ModuleType': <class 'module'>, 'spam': <module 'spam' from
'/home/mats/spam.py'>}
>>> spam.__dict__
{'__name__': 'spam', '__doc__': None, '__package__': '',  'a': <function
a at 0x7f7aba268b00>}

If you import with "from" or "as", then the exact same thing happens,
except for the last step: your namespace dictionary gets a reference to
what you asked for instead of a reference to the module object:

>>> from spam import a
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__':
None, '__annotations__': {}, '__builtins__': <module 'builtins'
(built-in)>, 'ModuleType': <class 'module'>, 'a': <function a at
0x7f7aba268b00>}
>>>

So the name 'a' in this module is now bound to the same function object
that the name 'a' is bound to in the spam module's namespace.


More information about the Tutor mailing list