There seems to be some confusion to what is going on with the __getself__ method. This is almost certainly dues to my lack of communicating things clearly. I am going to attempt to walk through what will happen in context of a code example. The important thing to keep in mind is that __getself__ is invoked only on named object access, i.e. LOAD_VALUE, and not on variables accessed from a container, or fetched from the stack (in the case of the cpython interpreter access. Say we have the following "expression template" from my examples.py. I will be using the types SimpleArray, and SimpleArrayExecutor, where the later has __getself__ defined. a, b, and c are instances of SimpleArray. d = a + b + c print(d) * a and b are named variables and are loaded from locals. * The defined add object is called, which returns a SimpleArrayExecutor which is placed back on the stack * this anonymous object is passed along with c to the add operator defined on SimpleArrayExecutor * the result is returned and bound to the name d * print is loaded onto the stack * d is loaded, and since it is named, its __getself__ is triggered, a single loop over the arrays happens, a new SimpleArray is constructed and is placed on the stack. * The call instruction is called with print and the returned SimpleArray on the stack. now for a similar case tmp = a + b d = tmp + c print(d) * a and be are loaded from locals * the call instruction happens with the defined add method * The result is a SimpleArrayExecutor and it is bound to the name tmp * tmp is accessed, because it defines __getself__ it is executed where a loop happens, and a SimpleArray is put onto the stack * c is loaded onto the stack and the call instruction is called with the add method * The result is a SimpleArrayExecutor and is stored with the name d * d is loaded, and since it is named, its __getself__ is triggered, a single loop over the arrays happens, a new SimpleArray is constructed and is placed on the stack. * The call instruction is called with print and the returned SimpleArray on the stack. This results in the same result, but with an extra loop. This can be avoided by using the built in getcloaked (the function name is up in the air) similar to the object.__getattr__ escape hatch. I.E.: tmp = a + b d = getcloaked(tmp) + c prtint(d) Now the behavior is the same as the first case, as getcloaked returns the metavariable that has not been bound to a name and so it is loaded right on the stack. There are two (three) important cases when I have exempt __getself__ from being called. First is when an object is used in methods defined within itself. This means that self can be used when defining methods without triggering recursive behavior. The other cases are calling or returning from a function. This is to ensure the following say consistent. f1(): x = MetaVar() return x f2(): return MetaVar() In f1 the return function evaluates if its return argument is the result of a metavar __getself__ call and if so, returns the metavar instead. This is all done behind what is essentially if (x != NULL) code blocks in c, so that the runtime hit on any code that does not use this feature is kept to a minimum. On Thu, Jun 27, 2019 at 9:41 AM Chris Angelico <rosuav@gmail.com> wrote:
On Thu, Jun 27, 2019 at 11:11 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Thu, Jun 27, 2019 at 12:46:58AM +1000, Chris Angelico wrote:
There are many things that can be implemented with dunders, yes, but in Python, I would expect these two functions to behave identically:
def f1(x): return frob(x).spam
def f2(x): f = frob(x) s = f.spam return s
This correlation is critical to sane refactoring.
I'm not convinced that this is going to change under the proposal. Since neither f nor s already exist, they cannot overload assignment. Unless something in Nate's proposal is quite different from earlier concrete proposals, I don't think this is a slam-dunk criticism. I think that it is a problem is theory but not in practice.
That would be true if the proposal were only for __setself__, but the __getself__ part makes things more complicated. I'm not 100% sure because I don't fully understand the proposal, but if the object returned by frob(x) has a __getself__ method, I think it would be called in f2 but NOT in f1 (because referencing the name "f" triggers the get, whereas simply chaining ".spam" onto the end of the function call doesn't).
Does that change your view of it?
ChrisA _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/TK3EFW... Code of Conduct: http://python.org/psf/codeofconduct/
-- Nate Lust, PhD. Astrophysics Dept. Princeton University