Re: From parsing a class to code object to class to mappingproxy to object (oh my!)

2019-03-31 Thread Gregory Ewing

adam.pre...@gmail.com wrote:

What is the plumbing taking the result of that code object over to this
proxy? I'm assuming __build_class__ runs that code object and then starts
looking for new names and see to create this. 



Is this mapping proxy the
important thing for carrying the method declaration?


No, the mapping proxy is only there to prevent Python code from directly
accessing the dict holding the class's attributes. (If that were
allowed, bad things could be done that would crash the interpreter.)

There's a fairly good analysis of what __build_class__ does here:

https://eli.thegreenplace.net/2012/06/15/under-the-hood-of-python-class-definitions

Briefly, it creates a dict to serve as the class's namespace dict,
then executes the class body function passed to it, with that dict
as the local namespace. So method defs and other assignments go
straight into what will become the class namespace when the class
object is created.


I'm then assuming that in object construction, this proxy is carried by some
reference to the final object in such a way that if the class's fields are
modified, all instances would see the modification unless the local object
itself was overridden.


There's nothing fancy going on at that stage. The object contains
a reference to its class, that's all. If an attribute is not found
in the object, it is then looked for in the namespace of its class,
then its base classes in mro order. (Actually it's more complicated
than that to allow for descriptors, but that's the basic idea.)

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


Re: Syntax for one-line "nonymous" functions in "declaration style"

2019-03-31 Thread Ian Kelly
On Sun, Mar 31, 2019 at 1:09 PM Alexey Muranov 
wrote:
>
> On dim., Mar 31, 2019 at 6:00 PM, python-list-requ...@python.org wrote:
> > On Sat, Mar 30, 2019, 5:32 AM Alexey Muranov
> > 
> > wrote:
> >
> >>
> >>  On ven., Mar 29, 2019 at 4:51 PM, python-list-requ...@python.org
> >> wrote:
> >>  >
> >>  > There could perhaps be a special case for lambda expressions such
> >>  >  that,
> >>  > when they are directly assigned to a variable, Python would use
> >> the
> >>  > variable name as the function name. I expect this could be
> >>  >  accomplished by
> >>  > a straightforward transformation of the AST, perhaps even by just
> >>  >  replacing
> >>  > the assignment with a def statement.
> >>
> >>  If this will happen, that is, if in Python assigning a
> >> lambda-defined
> >>  function to a variable will mutate the function's attributes, or
> >> else,
> >>  if is some "random" syntactically-determined cases
> >>
> >>  f = ...
> >>
> >>  will stop being the same as evaluating the right-hand side and
> >>  assigning the result to "f" variable, it will be a fairly good extra
> >>  reason for me to go away from Python.
> >>
> >
> > Is there a particular reason you don't like this? It's not too
> > different
> > from the syntactic magic Python already employs to support the
> > 0-argument
> > form of super().
>
> I do not want any magic in a programming language i use, especially if
> it breaks simple rules.
>
> I do not like 0-argument `super()` either, but at least I do not have
> to use it.

Well, you wouldn't have to use my suggestion either, since it only applies
to assignments of the form "f = lambda x: blah". As has already been
stated, the preferred way to do this is with a def statement. So just use a
def statement for this, and it wouldn't affect you (unless you *really*
want the function's name to be "" for some reason).

That said, that's also the reason why this probably wouldn't happen. Why go
to the trouble of fixing people's lambda assignments for them when the
preferred fix would be for them to do it themselves by replacing them with
def statements?

> Neither i like how a function magically turns into a generator if the
> keyword `yield` appears somewhere within its definition.

I agree, there should have been a required syntactic element on the "def"
line as well to signal it immediately to the reader. It won't stop me from
using them, though.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Syntax for one-line "nonymous" functions in "declaration style"

2019-03-31 Thread Alexey Muranov

On dim., Mar 31, 2019 at 6:00 PM, python-list-requ...@python.org wrote:
On Sat, Mar 30, 2019, 5:32 AM Alexey Muranov 


wrote:



 On ven., Mar 29, 2019 at 4:51 PM, python-list-requ...@python.org 
wrote:

 >
 > There could perhaps be a special case for lambda expressions such
 >  that,
 > when they are directly assigned to a variable, Python would use 
the

 > variable name as the function name. I expect this could be
 >  accomplished by
 > a straightforward transformation of the AST, perhaps even by just
 >  replacing
 > the assignment with a def statement.

 If this will happen, that is, if in Python assigning a 
lambda-defined
 function to a variable will mutate the function's attributes, or 
else,

 if is some "random" syntactically-determined cases

 f = ...

 will stop being the same as evaluating the right-hand side and
 assigning the result to "f" variable, it will be a fairly good extra
 reason for me to go away from Python.



Is there a particular reason you don't like this? It's not too 
different
from the syntactic magic Python already employs to support the 
0-argument

form of super().


I do not want any magic in a programming language i use, especially if 
it breaks simple rules.


I do not like 0-argument `super()` either, but at least I do not have 
to use it. I am suspicious of `__class__` too. But here only 
identifiers are hacked, not the assignment operator. (I suppose the 
hack can be unhacked by using your own meta-class with a custom 
`__prepare__`.)


Neither i like how a function magically turns into a generator if the 
keyword `yield` appears somewhere within its definition.


Those are the things i don't like the most in Python.

Alexey.


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


From parsing a class to code object to class to mappingproxy to object (oh my!)

2019-03-31 Thread adam . preble
I have been mimicking basic Python object constructs successfully until I 
started trying to handle methods as well in my hand-written interpreter. At 
that point, I wasn't sure where to stage all the methods before they get 
shuffled over to an actual instance of an object. I'm having to slap this out 
here partially to rubber duck it and partially because I really don't know 
what's going on.

Here's something tangible we can use:
>>> def construct():
...   class Meow:
... def __init__(self):
...   self.a = 1
... def change_a(self, new_a):
...   self.a = new_a
...   return Meow()
...
>>> dis(construct)
  2   0 LOAD_BUILD_CLASS
  2 LOAD_CONST   1 (", line 2>)
  4 LOAD_CONST   2 ('Meow')
  6 MAKE_FUNCTION0
  8 LOAD_CONST   2 ('Meow')
 10 CALL_FUNCTION2
 12 STORE_FAST   0 (Meow)

  7  14 LOAD_FAST0 (Meow)
 16 CALL_FUNCTION0
 18 RETURN_VALUE

I've wrapped my class in a function so I could more readily poke it with a 
stick. I understand LOAD_BUILD_CLASS will invoke builtins.__build_class__(). By 
the way, why the special opcode for that? Anyways, it takes that code object, 
which looks to be particularly special.

Note that I'm inserting some newlines and extra junk for sanity:

>>> import ctypes
>>> c = ctypes.cast(0x021BD59170C0, ctypes.py_object).value
>>> c.co_consts
('construct..Meow',
", line 3>,
'construct..Meow.__init__',
", line 5>,
'construct..Meow.change_a',
None)

>>> c.co_names
('__name__', '__module__', '__qualname__', '__init__', 'change_a')

>>> dis(c.co_code)
  0 LOAD_NAME0 (0) -> __name__ ...
  2 STORE_NAME   1 (1) -> ... goes into __module__
  4 LOAD_CONST   0 (0) -> Name of the class = 
'construct..Meow' ...
  6 STORE_NAME   2 (2) -> ... goes into __qualname__
  8 LOAD_CONST   1 (1) -> __init__ code object
 10 LOAD_CONST   2 (2) -> The name "__init__" ...
 12 MAKE_FUNCTION0 -> ... Made into a function
 14 STORE_NAME   3 (3) -> Stash it
 16 LOAD_CONST   3 (3) -> The name "change_a" ...
 18 LOAD_CONST   4 (4) -> The __change_a__ code object ...
 20 MAKE_FUNCTION0 -> ... Made into a function
 22 STORE_NAME   4 (4) -> Stash it
 24 LOAD_CONST   5 (5) -> Returns None
 26 RETURN_VALUE

I'm not too surprised to see stuff like this since this kind of thing is what I 
expect to find in flexible languages that do object-oriented programming by 
basically blessing a variable and heaping stuff on it. It's just that I'm 
trying to figure out where this goes in the process of language parsing to 
class declaration to object construction.

What I'm assuming is that when builtins.__build_class__() is invoked, it does 
all the metaclass/subclass chasing first, and then ultimately invokes this code 
object to populate the class. If I look at the __dict__ for the class 
afterwards, I see:

mappingproxy(
{'__module__': '__main__',
'__init__': .Meow.__init__ at 0x021BD592AAE8>,
'change_a': .Meow.change_a at 0x021BD5915F28>,
'__dict__': ,
'__weakref__': ,
'__doc__': None})

What is the plumbing taking the result of that code object over to this proxy? 
I'm assuming __build_class__ runs that code object and then starts looking for 
new names and see to create this. Is this mapping proxy the important thing for 
carrying the method declaration?

Is this also where prepare (and __prepare__) comes into play? Running into that 
was where I felt the need to start asking questions because I got six layers 
deep and my brain melted.

I'm then assuming that in object construction, this proxy is carried by some 
reference to the final object in such a way that if the class's fields are 
modified, all instances would see the modification unless the local object 
itself was overridden.
-- 
https://mail.python.org/mailman/listinfo/python-list