[prev in list] [next in list] [prev in thread] [next in thread] 

List:       python-ideas
Subject:    Re: [Python-ideas] LOAD_NAME/LOAD_GLOBAL should be use getattr()
From:       C Anthony Risinger <c () anthonyrisinger ! com>
Date:       2017-09-14 17:41:37
Message-ID: CAGAVQTEYoHeuXPFS4poR3t3rtppc_haoOjE19phk18JFkes5Sw () mail ! gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


On Thu, Sep 14, 2017 at 8:07 AM, Steven D'Aprano <steve@pearwood.info>
wrote:

> On Wed, Sep 13, 2017 at 12:24:31PM +0900, INADA Naoki wrote:
> > I'm worring about performance much.
> >
> > Dict has ma_version from Python 3.6 to be used for future optimization
> > including global caching.
> > Adding more abstraction layer may make it difficult.
>
> Can we make it opt-in, by replacing the module __dict__ when and only if
> needed? Perhaps we could replace it on the fly with a dict subclass that
> defines __missing__? That's virtually the same as __getattr__.
>
> Then modules which haven't replaced their __dict__ would not see any
> slow down at all.
>
> Does any of this make sense, or am I talking nonsense on stilts?
>

This is more or less what I was describing here:

https://mail.python.org/pipermail/python-ideas/2017-September/047034.html

I am also looking at Neil's approach this weekend though.

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:

* 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:

```
global __class__
global __self__

class __class__:
    def __new__(... namespace-dunders-and-builtins-passed-as-kwds ...):
        # ... module code ...
        # ... closures may access __self__ and __class__ ...
        return FancyModule(__name__)

__self__ = __class__(__builtins__={...}, __name__='fancy', ...)
sys.modules[__self__.__name__] = __self__
```

* 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:

```
global __class__
global __self__

def __hidden_TOS(... namespace-dunders-and-builtins-passed-as-kwds ...):
    # ... initial module code ...
    # ... closures may access __self__ and __class__ ...
    module = yield FancyModuleInitialThatMightRaiseIfUsed(__name__)
    # ... more module code ...
    module.__class__ = FancyModule

for __self__ in __hidden_TOS(__builtins__={...}, __name__='fancy', ...):
    __class__ = __self__.__class__
    sys.modules[__self__.__name__] = __self__
```

Otherwise I still have a few ideas around using what we've got, possibly in
a backwards compatible way:

```
global __builtins__ = {...}
global __class__
global __self__

# Loader dunders.
__name__ = 'fancy'

# Deferred loading could likely stop this from raising in most cases.
# globals is a deferred import dict using __missing__.
# possibly sys.modules itself does deferred imports using __missing__.
sys.modules[__name__] = RaiseIfTouchedElseReplaceAllRefs(globals())

class __class__:
    [global] import current_module # ref in cells replaced with __self__
    [global] import other_module

    def bound_module_function(...):
        pass

    [global] def simple_module_function(...):
        pass

    # ... end module body ...

    # Likely still a descriptor.
    __dict__ = globals()

__self__ = __class__()
sys.modules[__self__.__name__] = __self__
 ```

Something to think about.

Thanks,

-- 

C Anthony

[Attachment #5 (text/html)]

<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Sep 14, 2017 \
at 8:07 AM, Steven D&#39;Aprano <span dir="ltr">&lt;<a \
href="mailto:steve@pearwood.info" target="_blank">steve@pearwood.info</a>&gt;</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> &gt; \
I&#39;m worring about performance much.<br> &gt;<br>
&gt; Dict has ma_version from Python 3.6 to be used for future optimization<br>
&gt; including global caching.<br>
&gt; 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&#39;s virtually the same as __getattr__.<br>
<br>
Then modules which haven&#39;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&#39;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 &quot;new-style&quot; \
module would preferably avoid the need to populate `sys.modules` with something that \
can&#39;t possibly exist yet (since it&#39;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 &quot;new-style&quot; 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__=&#39;fancy&#39;, \
...)</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&#39;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__=&#39;fancy&#39;, ...):</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&#39;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__ = \
&#39;fancy&#39;</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>



_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic