Re: From parsing a class to code object to class to mappingproxy to object (oh my!)
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"
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"
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!)
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