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 <ros...@gmail.com> wrote:

> On Thu, Jun 27, 2019 at 11:11 PM Steven D'Aprano <st...@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-le...@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/TK3EFWG6OHXA2UQ7DF7RLIBPRHQDR77I/
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
Nate Lust, PhD.
Astrophysics Dept.
Princeton University
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@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/DRGLGOWL4O4U4RVC4PUTEB72UYFYZQ74/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to