On Mon, 2021-01-11 at 17:56 -0800, Larry Hastings wrote:

On 1/11/21 5:02 PM, Paul Bryan wrote:

Some more questions...

"Binding"," bound" and "unbound" code objects:
Is your use of "binding" terminology in the PEP identical to the binding of a function to an object instance as a method during object creation?

I'm not.  In PEP 649 I think every reference of "binding" is talking about binding a code object to a globals dict to produce a function object.   The process of binding a function to an object instance to make a method is conceptually very similar, but distinct.

(and btw, functions aren't bound to their object to make methods during object creation, it's done lazily at the time you ask for it--that's what the "descriptor protocol" is all about!)

I think it'd be worth briefly describing binding, to avoid confusion. I'm now more educated on function/method binding lifecycle though, so bonus! ðŸ™‚

Function Annotations:

When binding an unbound annotation code object, a function will use its own __globals__ as the new function's globals.
I'm having trouble parsing this. Does this mean the newly bound __co_annotations__ function will inherit __globals__ from the function it's annotating?

Yes.  Though I wouldn't use "inherit", I'd just say it "uses" the __globals__ from the function.


Then I think this solves my particular scoping problem with 3.10 string-evaluated annotations!

Exceptions:
It's quite possible for a __co_annotation__ function call to raise an exception (e.g. NameError). When accessing __annotations__, if such an exception is raised during the call to __co_annotations__, what is the expected behavior?

If the function fails for any reason--throws an exception, or just doesn't return an acceptable value--then the getter immediately exits, and the internal state of the object is unchanged.  If you wanted to, you could catch the exception, fix the error, and get __annotations__ again, and it'd work.

OK.

s/__co_//?:
I'm probably naive, but is there a reason that one could not just store a callable in __annotations__, and use the descriptor to resolve it to a dictionary and store it when it is accessed? It would be one less dunder in the Python data model.

That would work, but I think the API is a bit of a code smell.  __annotations__ would no longer be stable:

a.__annotations__ = o
assert a.__annotations__ == o

Would that assert fail?  It depends on what type(o) is, which is surprising.


Equally surprising?:

a.__co_annotations__ = o
a.__annotations__
assert a.__co_annotations__ == o

Paul