Re: Why generate POP_TOP after an "import from?"

2020-04-18 Thread Chris Angelico
On Sun, Apr 19, 2020 at 7:40 AM Adam Preble  wrote:
>
> On Saturday, April 18, 2020 at 1:15:35 PM UTC-5, Alexandre Brault wrote:
> >  >>> def f():
> > ... â  â  from sys import path, argv ...
>
> So I figured it out and all but I wanted to ask about the special characters 
> in that output. I've seen that a few times and never figured out what's going 
> on and if I need to change how I'm reading these. Or say:
>
>  â â â â â â â â â â â â  12 STORE_FASTâ â â â â â â â â â â â â â  1 (argv
>
> I don't know if you're seeing all these letter a's. I'm guessing something 
> goofy with Unicode spaces or something?
>

That looks like something got messed up between the various mailing
list and newsgroup gateways. I'm not sure exactly what happened, but
it's probably been converted into nonbreaking spaces, then encoded in
some way, and decoded incorrectly. I'm not sure WHAT the encodings in
question would be, but my best guess is that the nonbreaking spaces
were encoded UTF-8 (C2 A0), and then decoded in some eight-bit
encoding.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why generate POP_TOP after an "import from?"

2020-04-18 Thread Chris Angelico
On Sun, Apr 19, 2020 at 7:36 AM Adam Preble  wrote:
>
> On Friday, April 17, 2020 at 1:37:18 PM UTC-5, Chris Angelico wrote:
> > The level is used for package-relative imports, and will basically be
> > the number of leading dots (eg "from ...spam import x" will have a
> > level of 3). You're absolutely right with your analysis, with one
> > small clarification:
>
> Thanks for taking that on too. I haven't set up module hierarchy yet so I'm 
> not in a position to handle levels, but I have started parsing them and 
> generating the opcodes. Is it sufficient to just use the number of dots as an 
> indication of level?
>

Correct. You can literally just put that exact line of code into a
function, disassemble it, and you'll see the level - even if you're
not in a package (which would be a run-time error only).

> As a side note, I suppose it's sufficient to just *peek* at the stack rather 
> than pop the module and push it again. I'm guessing that's what the Python 
> interpreter is doing.
>

Yep!

> > In theory, I suppose, you could replace the POP_TOP with a STORE_FAST
> > into "sys", and thus get a two-way import that both grabs the module
> > and also grabs something out of it. Not very often wanted, but could
> > be done if you fiddle with the bytecode.
>
> I'm trying to follow along for academic purposes. I'm guessing you mean that 
> would basically optimize:
>
> from sys import path
> import sys
>
> It would definitely be a fringe thing to do...

Exactly, an incredibly fringe thing to do :) But that's the effect
you'd get (at least, I believe so - haven't actually tested that).

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why generate POP_TOP after an "import from?"

2020-04-18 Thread Adam Preble
On Saturday, April 18, 2020 at 1:15:35 PM UTC-5, Alexandre Brault wrote:
>  >>> def f():
> ... â  â  from sys import path, argv ...

So I figured it out and all but I wanted to ask about the special characters in 
that output. I've seen that a few times and never figured out what's going on 
and if I need to change how I'm reading these. Or say:

 â â â â â â â â â â â â  12 STORE_FASTâ â â â â â â â â â â â â â  1 (argv

I don't know if you're seeing all these letter a's. I'm guessing something 
goofy with Unicode spaces or something?
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why generate POP_TOP after an "import from?"

2020-04-18 Thread Adam Preble
On Friday, April 17, 2020 at 1:37:18 PM UTC-5, Chris Angelico wrote:
> The level is used for package-relative imports, and will basically be
> the number of leading dots (eg "from ...spam import x" will have a
> level of 3). You're absolutely right with your analysis, with one
> small clarification:

Thanks for taking that on too. I haven't set up module hierarchy yet so I'm not 
in a position to handle levels, but I have started parsing them and generating 
the opcodes. Is it sufficient to just use the number of dots as an indication 
of level?

As a side note, I suppose it's sufficient to just *peek* at the stack rather 
than pop the module and push it again. I'm guessing that's what the Python 
interpreter is doing.

> In theory, I suppose, you could replace the POP_TOP with a STORE_FAST
> into "sys", and thus get a two-way import that both grabs the module
> and also grabs something out of it. Not very often wanted, but could
> be done if you fiddle with the bytecode.

I'm trying to follow along for academic purposes. I'm guessing you mean that 
would basically optimize:

from sys import path
import sys

It would definitely be a fringe thing to do...
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why generate POP_TOP after an "import from?"

2020-04-17 Thread Alexandre Brault

On 2020-04-17 2:22 p.m., Adam Preble wrote:

Given this in Python 3.6.8:

from dis import dis

def import_from_test():
from sys import path


dis(import_from_test)

   2   0 LOAD_CONST   1 (0)
   2 LOAD_CONST   2 (('path',))
   4 IMPORT_NAME  0 (sys)
   6 IMPORT_FROM  1 (path)
   8 STORE_FAST   0 (path)
  10 POP_TOP
  12 LOAD_CONST   0 (None)
  14 RETURN_VALUE

I don't understand why there's a POP_TOP there that I don't get for an 
import_name grammatical statement.

IMPORT_NAME needs to eat the top two entries of the stack for level and the 
from-list. BTW I don't know what level is for either since my science projects 
have always had it be zero, but that's another question.

IMPORT_NAME will the push the module on to the stack.

IMPORT_FROM will import path from the module on the stack, and push that result 
on the stack.

STORE_FAST will store path for use, finally "modifying the namespace."

At this point, my conceptual stack is empty. If I POP_TOP then I have nothing 
to pop and the world would end. Yet, it doesn't. What am I missing?


You can get an idea of what you're missing if you import multiple names 
from a module at once:


>>> def f():
...     from sys import path, argv
...
>>> dis.dis(f)
  2   0 LOAD_CONST   1 (0)
  2 LOAD_CONST   2 (('path', 'argv'))
  4 IMPORT_NAME  0 (sys)
  6 IMPORT_FROM  1 (path)
  8 STORE_FAST   0 (path)
 10 IMPORT_FROM  2 (argv)
 12 STORE_FAST   1 (argv)
 14 POP_TOP
 16 LOAD_CONST   0 (None)
 18 RETURN_VALUE

As shown here (and confirmed by the doc of the IMPORT_FROM opcode), 
IMPORT_FROM loads an attribute from the module on top of the stack, but 
doesn't pop the module. The POP_TOP instruction is what does.


--
https://mail.python.org/mailman/listinfo/python-list


Re: Why generate POP_TOP after an "import from?"

2020-04-17 Thread Chris Angelico
On Sat, Apr 18, 2020 at 4:26 AM Adam Preble  wrote:
>
> Given this in Python 3.6.8:
>
> from dis import dis
>
> def import_from_test():
>from sys import path
>
> >>> dis(import_from_test)
>   2   0 LOAD_CONST   1 (0)
>   2 LOAD_CONST   2 (('path',))
>   4 IMPORT_NAME  0 (sys)
>   6 IMPORT_FROM  1 (path)
>   8 STORE_FAST   0 (path)
>  10 POP_TOP
>  12 LOAD_CONST   0 (None)
>  14 RETURN_VALUE
>
> I don't understand why there's a POP_TOP there that I don't get for an 
> import_name grammatical statement.
>
> IMPORT_NAME needs to eat the top two entries of the stack for level and the 
> from-list. BTW I don't know what level is for either since my science 
> projects have always had it be zero, but that's another question.
>
> IMPORT_NAME will the push the module on to the stack.
>
> IMPORT_FROM will import path from the module on the stack, and push that 
> result on the stack.
>
> STORE_FAST will store path for use, finally "modifying the namespace."
>
> At this point, my conceptual stack is empty. If I POP_TOP then I have nothing 
> to pop and the world would end. Yet, it doesn't. What am I missing?
>

Good question, and nicely put, thank you. I like questions like this :)

Here's another function that can showcase a bit more of what's going on:

>>> def f():
... from . import foo, bar, baz
...
>>> dis.dis(f)
  2   0 LOAD_CONST   1 (1)
  2 LOAD_CONST   2 (('foo', 'bar', 'baz'))
  4 IMPORT_NAME  0
  6 IMPORT_FROM  1 (foo)
  8 STORE_FAST   0 (foo)
 10 IMPORT_FROM  2 (bar)
 12 STORE_FAST   1 (bar)
 14 IMPORT_FROM  3 (baz)
 16 STORE_FAST   2 (baz)
 18 POP_TOP
 20 LOAD_CONST   0 (None)
 22 RETURN_VALUE

The level is used for package-relative imports, and will basically be
the number of leading dots (eg "from ...spam import x" will have a
level of 3). You're absolutely right with your analysis, with one
small clarification:

> IMPORT_FROM will import path from the module on the stack, and push that 
> result on the stack.
>

It leaves the module on the stack, allowing chained IMPORT_FROM
operations to grab multiples from the same module. That's why it needs
to be popped off at the end.

In theory, I suppose, you could replace the POP_TOP with a STORE_FAST
into "sys", and thus get a two-way import that both grabs the module
and also grabs something out of it. Not very often wanted, but could
be done if you fiddle with the bytecode.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why generate POP_TOP after an "import from?"

2020-04-17 Thread Adam Preble
On Friday, April 17, 2020 at 1:22:18 PM UTC-5, Adam Preble wrote:

> At this point, my conceptual stack is empty. If I POP_TOP then I have nothing 
> to pop and the world would end. Yet, it doesn't. What am I missing?

Check out this guy replying to himself 10 minutes later.

I guess IMPORT_FROM pushes the module back on to the stack afterwards so that 
multiple import-from's can be executed off of it. This is then terminated with 
a POP_TOP:

>>> def import_from_multi():
... from sys import path, bar
...
>>> dis(import_from_multi)
  2   0 LOAD_CONST   1 (0)
  2 LOAD_CONST   2 (('path', 'bar'))
  4 IMPORT_NAME  0 (sys)
  6 IMPORT_FROM  1 (path)
  8 STORE_FAST   0 (path)
 10 IMPORT_FROM  2 (bar)
 12 STORE_FAST   1 (bar)
 14 POP_TOP
 16 LOAD_CONST   0 (None)
 18 RETURN_VALUE
-- 
https://mail.python.org/mailman/listinfo/python-list


Why generate POP_TOP after an "import from?"

2020-04-17 Thread Adam Preble
Given this in Python 3.6.8:

from dis import dis

def import_from_test():
   from sys import path

>>> dis(import_from_test)
  2   0 LOAD_CONST   1 (0)
  2 LOAD_CONST   2 (('path',))
  4 IMPORT_NAME  0 (sys)
  6 IMPORT_FROM  1 (path)
  8 STORE_FAST   0 (path)
 10 POP_TOP
 12 LOAD_CONST   0 (None)
 14 RETURN_VALUE

I don't understand why there's a POP_TOP there that I don't get for an 
import_name grammatical statement.

IMPORT_NAME needs to eat the top two entries of the stack for level and the 
from-list. BTW I don't know what level is for either since my science projects 
have always had it be zero, but that's another question.

IMPORT_NAME will the push the module on to the stack.

IMPORT_FROM will import path from the module on the stack, and push that result 
on the stack.

STORE_FAST will store path for use, finally "modifying the namespace."

At this point, my conceptual stack is empty. If I POP_TOP then I have nothing 
to pop and the world would end. Yet, it doesn't. What am I missing?
-- 
https://mail.python.org/mailman/listinfo/python-list