<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Sep 14, 2017 at 8:07 AM, Steven D'Aprano <span dir="ltr"><<a href="mailto:steve@pearwood.info" target="_blank">steve@pearwood.info</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="gmail-">On Wed, Sep 13, 2017 at 12:24:31PM +0900, INADA Naoki wrote:<br>
> I'm worring about performance much.<br>
><br>
> Dict has ma_version from Python 3.6 to be used for future optimization<br>
> including global caching.<br>
> Adding more abstraction layer may make it difficult.<br>
<br>
</span>Can we make it opt-in, by replacing the module __dict__ when and only if<br>
needed? Perhaps we could replace it on the fly with a dict subclass that<br>
defines __missing__? That's virtually the same as __getattr__.<br>
<br>
Then modules which haven't replaced their __dict__ would not see any<br>
slow down at all.<br>
<br>
Does any of this make sense, or am I talking nonsense on stilts?<br></blockquote><div><br></div><div>This is more or less what I was describing here:</div><div><br></div><div><a href="https://mail.python.org/pipermail/python-ideas/2017-September/047034.html">https://mail.python.org/pipermail/python-ideas/2017-September/047034.html</a><br></div><div><br></div><div>I am also looking at Neil's approach this weekend though.</div><div><br></div><div>I would be happy with a __future__ that enacted whatever concessions are necessary to define a module as if it were a class body, with import statements maybe being implicitly global. This "new-style" module would preferably avoid the need to populate `sys.modules` with something that can't possibly exist yet (since it's being defined!). Maybe we allow module bodies to contain a `return` or `yield`, making them a simple function or generator? The presence of either would activate this "new-style" module loading:</div><div><br></div><div>* Modules that call `return` should return the completed module. Importing yourself indirectly would likely cause recursion or be an error (lazy importing would really help here!). Could conceptually expand to something like:</div><div><br></div><div>```</div><div>global __class__<br></div><div>global __self__<br></div><div><br></div><div>class __class__:</div><div>    def __new__(... namespace-dunders-and-builtins-passed-as-kwds ...):</div><div>        # ... module code ...</div><div>        # ... closures may access __self__ and __class__ ...</div><div>        return FancyModule(__name__)</div><div><br></div><div>__self__ = __class__(__builtins__={...}, __name__='fancy', ...)</div><div>sys.modules[__self__.__name__] = __self__</div><div>```</div><div><br></div><div>* Modules that call `yield` should yield modules. This could allow defining zero modules, multiple modules, overwriting the same module multiple times. Module-level code may then yield an initial object so self-referential imports, in lieu of deferred loading, work better. They might decide to later upgrade the initial module's __class__ (similar to today) or replace outright. Could conceptually expand to something like:</div><div><div><br class="gmail-Apple-interchange-newline">```</div><div>global __class__<br></div><div>global __self__<br></div><div><br></div><div>def __hidden_TOS(... namespace-dunders-and-builtins-passed-as-kwds ...):<br></div><div>    # ... initial module code ...</div><div>    # ... closures may access __self__ and __class__ ...<br></div><div>    module = yield FancyModuleInitialThatMightRaiseIfUsed(__name__)</div><div>    # ... more module code ...<br></div><div>    module.__class__ = FancyModule</div><div><div><br></div><div>for __self__ in __hidden_TOS(__builtins__={...}, __name__='fancy', ...):</div><div>    __class__ = __self__.__class__<br></div><div>    sys.modules[__self__.__name__] = __self__</div></div><div>```</div></div><div><br></div><div>Otherwise I still have a few ideas around using what we've got, possibly in a backwards compatible way:</div><div><br></div><div>```</div><div>global __builtins__ = {...}<br></div><div>global __class__<br></div><div>global __self__<br></div><div><br></div><div># Loader dunders.</div><div>__name__ = 'fancy'</div><div><br></div><div># Deferred loading could likely stop this from raising in most cases.</div><div># globals is a deferred import dict using __missing__.<br></div><div># possibly sys.modules itself does deferred imports using __missing__.<br></div><div>sys.modules[__name__] = RaiseIfTouchedElseReplaceAllRefs(globals())</div><div><br></div><div>class __class__:</div><div>    [global] import current_module # ref in cells replaced with __self__</div><div>    [global] import other_module</div><div><div><br class="gmail-Apple-interchange-newline">    def bound_module_function(...):</div><div>        pass</div><div><br></div><div>    [global] def simple_module_function(...):</div><div>        pass</div></div><div><br></div><div>    # ... end module body ...<br></div><div><br></div><div>    # Likely still a descriptor.<br></div><div>    __dict__ = globals()<br></div><div><div><br class="gmail-Apple-interchange-newline">__self__ = __class__()</div><div>sys.modules[__self__.__name__] = __self__</div></div><div> ```<br></div><div><br></div><div>Something to think about.</div><div><br></div><div>Thanks,</div><div><br></div><div>-- </div><div><br></div><div>C Anthony</div></div>
</div></div>