[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Stephen J. Turnbull
Christopher Barker writes:

 > This suggestion would mean that “=>” would create a deferred expression,
 > but it would not be a general purpose one.

I would prefer that "=>" create a general purpose evaluation-deferred
expression, but that the general-purpose one be tuned such that you
don't need new syntax to dereference it in the common use cases.

This generality might be implemented by a "context" attribute on the
object, or as Eric suggests it might be a rule that "deferred objects"
that are defined as default function arguments get evaluated before
the function body (ie, as in PEP 671, I think).

 > Though maybe there could be a way to evaluate it in a more general way,
 > kind of like eval — where you can control the namespaces used.

There is some such facility in Common Lisp, so I think this is quite
feasible.  There will be a lot of bikeshedding to be done about
*which* namespaces deserve the simplest syntax in *which* contexts.
Eg, I don't think there will be much disagreement about evaluating
"deferred objects" used as argument defaults just before the function
body is entered using the namespaces used in PEP 671, but the case of
an actual argument that is a "deferred object" probably would be more
contentious.

 > I guess what I’m suggesting is that we could create a very specific
 > kind of deferred object, and in the future expand it to more
 > general use.

I don't think this works very well.  At the very least, some effort
should go into thinking about potential generalization and reserving
some names in the class namespace so that all the good names don't get
taken by early user-derived classes.

I'm not sure this is a good example, but consider the case of Decimal
which has a lot of good properties from the point of view of "naive"
user expectations about numerical computations.  Unfortunately it was
late enough to the party that it's not vary attractive unless you
actually grok floating point; newbies are just going to use floats.
Of course Decimal has all the same kind of traps as float, but they're
far more familiar.  People expect 1/3 to result in an approximately
equal value; they do not expect 1/5 to do so.  I wonder if making
Decimal the default for decimal literals wouldn't be a good deal, but
I guess I'm gonna have to wonder forever. :-) [1]


Footnotes: 
[1]  *Not* intended as a suggestion.

___
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/HQ3GQKDTQFPFHNAP4BLOGIXNOYF7YV3E/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Steven D'Aprano
Okay, here we go:


```
import typing

def extract_docstrings(K):
"""Extract docstrings from the class K's annotations.

Class attribute docstrings are extracted from the second item
in Annotated[...] attributes. The original annotation is left
unchanged.

FIXME:
Handling of PEP 563 string annotations may not be best practice.

https://www.python.org/dev/peps/pep-0563/
"""
d = {}
for key, value in K.__annotations__.items():
if type(value) is str:
if value.startswith('Annotated[') and value.endswith(']'):
s = value[10: -1]
items = s.split(',')
if len(items) >= 2:
doc = items[1].strip()
d[key] = doc
elif typing.get_origin(value) is typing.Annotated:
d[key] = value.__metadata__[0]
K.__attrdocs__ = d
return K
```

And here's an example:

>>> @extract_docstrings
... class Lunch:
... spam: "Annotated[int, 'a delicious meat-like product']"
... eggs: Annotated[float, 'something that goes with spam']
... 
>>> Lunch.__attrdocs__
{'spam': "'a delicious meat-like product'", 'eggs': 'something that goes with 
spam'}



-- 
Steve
___
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/I4FZKLAVNMJ6OWICFU47JPZFII4DHRBY/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Steven D'Aprano
On Sun, Dec 12, 2021 at 12:38:06AM -0500, Ricky Teachey wrote:

> But Steve, since the most utilized documentation tool in the python
> universe, sphinx, doesn't look at Annotated

Yet.

> or in the lowercase-annotation part of an expression

Yet.

> for this and instead looks at a bare string below the
> member definition, and since I presume it had been doing this for a long
> time (before Annotated was added not long ago, and probably before the
> annotation too?), doesn't this mean that right now there are at least three
> competing ways being used to provide attribute docstrings?

And before we had PEP 484 there were multiple competing and 
incompatible conventions for putting type hints in docstrings.

https://www.python.org/dev/peps/pep-0484/

There are:

- Epytext (Javadoc style)
- ReST (Sphinx)
- Googledoc
- Numpydoc

although some of them may no longer be widely used.

https://stackoverflow.com/questions/3898572/what-are-the-most-common-python-docstring-formats

https://www.adrian.idv.hk/2018-02-18-docstring/

Static and runtime tools that wanted to get type hints had to guess the 
format and parse the docstring to get the types. Who still does that?

If dataclasses, and other classes, move to using Annotated and 
__attrdoc__ for docstrings, the tools will follow. Runtime tools will 
look at the dunder, static tools will look at the annotation directly.

**Which they will have to do anyway** if we add the convention that 
string literals following an assignment get recorded in __attrdoc__. 
Runtime tools will want to look in the dunder, not parse the source 
code. And static tools which aren't Sphinx will need to be adjusted to 
look at the string literals.

So either way the tooling has to change.

Sphinx is not the decider here. I dare say that they will want to 
continue supporting bare strings into the indefinite future, but new 
tools, and those with weaker backwards-compatibility constaints, will 
surely prefer to extract docstrings from __attrdoc__ than parsing the 
source code.


> As far as using the lowercase-annotation for the docstring: in a world of
> more and more type hinted python (to be clear: I don't always use type
> hints but I do like this world), if you want to make you don't create a
> problem later, using the annotation slot for your docstring:
> 
> x: "spam"
> 
> ... isn't really an option.

Of course it is. Just decorate your class with @no_type_hints.


> - without an official blessed agreement that the existing Annotated feature
> ought to be used for docstrings, there is little reason for other 3rd party
> help/documentation tools to look in that location for these docstrings

All it takes is literally one stdlib class to start doing it officially, 
and people will pay attention.


> I just think there's more to do here than add a decorator.

That depends on whether you mean, what do *we* need to do get the ball 
rolling, or what does the entire Python ecosystem need to do to 
transition to the day that every tool and library is actively using 
attribute docstrings both statically and at runtime?

Of course the second part is a bigger job.

But for the first, we can either (1):

* bikeshed this for another six ~~months~~ weeks;
* get at least one core dev to agree to sponsor a PEP;
* write a PEP;
* bikeshed some more;
* wait for the Steering Council to hopefully accept the PEP;
* modify the interpreter;
* wait for the new version to be available;

or we can (2)

* implement and support the feature today;

to get to the point that external tools can start using it.

I'm not kidding, if somebody cared enough to do this, they could 
probably have a patch for dataclasses to support this within a couple of 
hours and a plugin for Sphinx within a day.

(Spoken with the supreme confidence of somebody who knows that he will 
absolutely not have to do either.)

As far as I am concerned, this is exactly the sort of use-case that 
Annotated was invented for. Docstrings are metadata. Annotated is for 
attaching metadata to an annotation that is associated with some 
variable. Done and done.



-- 
Steve
___
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/4SMDBNO2FUQCJECDD6ILYK6RAQZ25TNP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Chris Angelico
On Sun, Dec 12, 2021 at 5:02 PM Stephen J. Turnbull
 wrote:
>
> Chris Angelico writes:
>  > On Sat, Dec 11, 2021 at 8:07 PM Stephen J. Turnbull
>  >  wrote:
>
>  > > This isn't about your proposal, it's about more general syntax.  Not
>  > > everything being discussed is about your proposal, and I suspect one
>  > > reason you have trouble figuring out what other people are talking
>  > > about is that you persistently try to force everything into that
>  > > context.
>  >
>  > Yes, it's silly of me to think of everything in a PEP 671 thread as if
>  > it's about argument defaults. Carrying on.
>
> Silly, no, I would say "human", but either way I believe it is
> impeding *your* understanding, and almost nobody else's.
>
> If you're not in *this* subthread to understand alternative ideas
> (again, *there is nothing wrong with ending this subthread here*), I
> have nothing further to say in it.  If you are, you need to calm down
> and start asking questions that specify what you want to know rather
> than adding a question mark to a grunt as in
>

By "alternative ideas", do you mean "alternative ways to implement
argument defaults", or "completely different ideas that have
absolutely nothing to do with argument defaults"? Because if it's the
latter, please, change the subject line so it isn't confusing. We can
have all manner of completely independent discussions happening at
once, and there's no problem. But if you mean "alternative ways to
implement argument defaults (and a bunch of other stuff too)", which
is what seemed to be the case when people said that PEP 671 should be
rescinded in favour of a more generic system, is it really wrong of me
to try to think of how this affects PEP 671?

Are you, or are you not, asking me to change or retract PEP 671? Does
your proposal in any way reflect upon argument defaults? Genuine
question. I am utterly, completely, Fblthp-level lost here.

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/6LE6EACLWNXZ2JOHRGXUJNBP65ZKHPVX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Stephen J. Turnbull
Chris Angelico writes:
 > On Sat, Dec 11, 2021 at 8:07 PM Stephen J. Turnbull
 >  wrote:

 > > This isn't about your proposal, it's about more general syntax.  Not
 > > everything being discussed is about your proposal, and I suspect one
 > > reason you have trouble figuring out what other people are talking
 > > about is that you persistently try to force everything into that
 > > context.
 > 
 > Yes, it's silly of me to think of everything in a PEP 671 thread as if
 > it's about argument defaults. Carrying on.

Silly, no, I would say "human", but either way I believe it is
impeding *your* understanding, and almost nobody else's.

Of course, the *thread* is generally about argument defaults, but
"everything" in it is not specifically about defaults.  In *this*
subthread Eric was arguing for waiting for a facility for *generic*
deferral of expression evaluation, and I was trying (unsuccessfully)
to see if your syntax for defaults could be extended to the more
generic idea.[1]  Elsewhere in the thread, you often ask about others'
ideas for such a facility, instead of saying "that's off-topic, you
have my proposal, let's keep discussion strictly to that" or
alternatively, "nobody claims that's more than vaporware, I say now is
better than never, nothing to see here, move on."  In that sense, yes,
you can treat everything in this thread as being about argument
defaults by cutting short any other discussion (or just ignoring it).
There's nothing wrong with doing that -- but you did not.  Instead you
talk about being confused, not understanding the suggested
alternatives, and you ask about them. In that context, it's on you to
try to channel others' thinking rather than demand that they channel
your confusion.

If you're not in *this* subthread to understand alternative ideas
(again, *there is nothing wrong with ending this subthread here*), I
have nothing further to say in it.  If you are, you need to calm down
and start asking questions that specify what you want to know rather
than adding a question mark to a grunt as in

 > How?


Footnotes: 
[1]  I think that's important because elsewhere I suggested that
defaults for actual arguments are a sufficiently important use case to
deserve separate syntax from the generic evaluation-deferring syntax
if needed.

___
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/3764RB4XOG7ML635A4UWY2JBDTZEJX4A/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Ricky Teachey
On Sat, Dec 11, 2021, 10:58 PM Steven D'Aprano  wrote:

> On Sat, Dec 11, 2021 at 05:02:39PM -0800, Christopher Barker wrote:
> > On Sat, Dec 11, 2021 at 3:03 PM Steven D'Aprano 
> wrote:
>
> > > Didn't we decide there was an existing feature for this, no need for
> > > new syntax?
>
> > Well, no. In fact, you could always put anything you wanted into an
> > annotation:
>
> Right, and we want to put a documentation string in it! :-)
>
>
> > Anyway, take a look at the docs for Annotated:
> >
> > https://docs.python.org/3/library/typing.html#typing.Annotated
> >
> > It has a number of possible unspecified uses, but fundamentally, it's
> about
> > the adding information to the type, not to the attribute -- e.g. not
> really
> > intended for docstrings.
>
> I don't think that the docs argue against this. Annotated is documented
> as the way to put arbitrary metadata into an annotation. What you do
> with it is up to the consumer of the metadata.
>
> The docs talk about this associating the metadata with the type, but
> that's because this is the *typing* module and *type* hints are still
> the primary use-case for annotations.
>
> And despite what the docs say, the metadata is actually, literally,
> associated with the variable (or its name at least). The annotation that
> gets stored in __annotations__ is **not**
>
> {T: "metadata"}
>
> as a naive reading of the docs might trick you into believing, but
>
> {"var": Annotated[T, "metadata"]}
>
>
> In any case, we can still use annotations for anything we like, and
> while typing is definitely and certainly the primary use for them, there
> will always be a way to opt-out. (Just don't run mypy!)
>
> Don't need type hints at all? Great, put your doc string as the
> annotation.
>
> μ: 'Number of steps from x0 to the start of the cycle.'
> λ: 'Length (period) of the cycle.'
> y: 'Value of f at the start of the cycle.' = None
>
> You might want to annotate the class with `no_type_check` if there is
> any chance the user might want to run mypy over your module, but that's
> entirely up to you.
>
> You do want type hints? Great, use Annotated. If there's an attribute
> that you don't want to give a type hint to, just use Any. (A small price
> to pay for using an existing feature, instead of waiting until Python
> 3.11 or 3.27 when it gets added to the core language.)
>
> μ: Annotated[int,
>  'Number of steps from x0 to the start of the cycle.']
> λ: Annotated[int, 'Length (period) of the cycle.']
> y: Annotated[Any,
>  'Value of f at the start of the cycle.'
>  ] = None
>
> No new syntax required. No bare strings floating around. You can
> generate the doc strings dynamically, they don't have to be literals.
>
> lunch: Annotated[Meal, ' '.join(['spam']*SPAM_COUNT)]
>
>
> > Sure, typing.Annotated *could* be used that way, but I don't think we can
> > say that the problem is solved.
>
> I think that from a language standpoint, we absolutely can say that the
> problem is solved. We don't need new syntax.
>
> We *might* want to standardise on a decorator or other tool to extract
> those docstrings, possibly sticking them in a new __attrdoc__ dunder.
> Being a dunder, we should get the core dev's approval for this, even if
> it is a third-party tool that uses it.
>
> (I assume we don't already use __attrdoc__ for something?)
>
> If the first use of this is dataclasses, then that would be de facto
> core dev approval.
>
> So we have a tool that takes an annotation:
>
> var: Annotated[T, docstring, *args]
>
> extracts out the docstring to an __attrdoc__ dunder:
>
> # Class.__attrdoc__
> {'var': docstring}
>
> and removes the annotation from the annotation:
>
> # Class.__annotation__
> {'var': Annotated[T, *args]}  # or just T if *args is empty?
>
> Dataclasses can automatically apply this tool (subject to backwards
> compatibility constraints), or we can apply it as a decorator to any
> other class we want.
>
> So we've gone from the *hard* problem of making a language change (new
> syntax, build the functionality into the interpreter) to the *easy*
> problem of writing a decorator.
>
>
> > Heck you could just as easily provide a tuple for the annotation:
> >
> > In [17]: class C:
> > ...: x: ("Doc string", int) = 123
> > ...:
>
>
> Sure, annotations can be anything you like. But external static typing
> tools may not support this, and will be confused or break. Same for
> third-party runtime tools.
>
> Best practice is to stick as closely to the standard type-hinting
> behaviour as you can, or to completely opt-out with no_type_hints.
>
>
> > The use cases for annotations are a bit up in the air at the moment --
> see
> > the ongoing discussion on python-dev. But I don't think there's any doubt
> > that any future endorsed use of them will be compatible with static
> typing
> > (if not restricted to it), so extending the use of annotations for
> > docstrings 

[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Adam Johnson
On Sat, 11 Dec 2021 at 16:30, Christopher Barker  wrote:
>
> Sorry, accidentally off-list.

I did exactly the same a few days ago.

On Thu, 9 Dec 2021 at 07:49, Chris Angelico  wrote:
>
> BTW, did you intend for this to be entirely off-list?

Nope, and apologies to all, but at least it's given me the opportunity
to correct a typo & do some slight reformatting. Here's it is:

On Thu, 9 Dec 2021 at 07:25, Adam Johnson  wrote:
>
> On Fri, 3 Dec 2021 at 22:38, Chris Angelico  wrote:
> >
> > On Sat, Dec 4, 2021 at 6:33 AM Adam Johnson  wrote:
> > > The first unwelcome surprise was:
> > >
> > > >>> def func(a=>[]):
> > > ... return a
> > > ...
> > >
> > > >>> import inspect
> > > >>> inspect.signature(func).parameters['a'].default
> > > Ellipsis
> > >
> > > Here the current behaviour of returning `Ellipsis` is very unfortunate,
> > > and I think could lead to a lot of head scratching — people wondering
> > > why they are getting ellipses in their code, seemingly from nowhere.
> > > Sure, it can be noted in the official documentation that `Ellipsis` is
> > > used as the indicator of late bound defaults, but third-party resources
> > > which aim to explain the uses of `Ellipsis` would (with their current
> > > content) leave someone clueless.
> >
> > Yes. Unfortunately, since there is fundamentally no object that can be
> > valid here, this kind of thing WILL happen. So when you see Ellipsis
> > in a default, you have to do one more check to figure out whether it's
> > a late-bound default, or an actual early-bound Ellipsis...
>
> My discomfort is that any code that doesn't do that extra check will
> continue to function, but incorrectly operate under the assumption that
> `Ellipsis` was the actual intended value. I wouldn't go so far as to say
> this is outright backwards-incompatible, but perhaps
> 'backwards-misleading'.
>
> When attempting to inspect a late-bound default I'd much rather an
> exception were raised than return value that, as far as any existing
> machinery is concerned, could be valid. (More on this thought later...)
>
> > > Additionally I don't think it's too unreasonable an expectation that,
> > > for a function with no required parameters, either of the following (or
> > > something similar) should be equivalent to calling `func()`:
> > >
> > > pos_only_args, kwds = [], {}
> > > for name, param in inspect.signature(func).parameters.items():
> > > if param.default is param.empty:
> > > continue
> > > elif param.kind is param.POSITIONAL_ONLY:
> > > pos_only_args.append(param.default)
> > > else:
> > > kwds[name] = param.default
> > >
> > > func(*pos_only_args, **kwds)
> > >
> > > # or, by direct access to the dunders
> > >
> > > func(*func.__defaults__, **func.__kwdefaults__)
> >
> > The problem is that then, parameters with late-bound defaults would
> > look like mandatory parameters. The solution is another check after
> > seeing if the default is empty:
> >
> > if param.default is ... and param.extra: continue
>
> In some situations, though, late-bound defaults do essentially become
> mandatory. Picking an example you posted yourself (when demonstrating
> that not using the functions own context could be surprising):
>
> def g(x=>(a:=1), y=>a): ...
>
> In your implementation `a` is local to `g` and gets bound to `1` when no
> argument is supplied for `x` and the default is evaluated, however
> **supplying an argument for `x` leaves `a` unbound**. Therefore, unless
> `y` is also supplied, the function immediately throws an
> `UnboundLocalError` when attempting to get the default for `y`.
>
> With the current implementation it is possible to avoid this issue, but
> it's fairly ugly — especially if calculating the value for `a` has side
> effects:
>
> def g(
> x => (a:=next(it)),
> y => locals()['a'] if 'a' in locals() else next(it),
> ): ...
>
> # or, if `a` is needed within the body of `g`
>
> def g(
> x => (a:=next(it)),
> y => locals()['a'] if 'a' in locals() else (a:=next(it)),
> ): ...
>
> > > The presence of the above if statement's first branch (which was
> > > technically unnecessary, since we established for the purpose of this
> > > example all arguments of `func` are optional / have non-empty defaults)
> > > hints that perhaps `inspect.Parameter` should grow another sentinel
> > > attribute similar to `Parameter.empty` — perhaps `Parameter.late_bound`
> > > — to be set as the `default` attribute of applicable `Parameter`
> > > instances (if not also to be used as the sentinel in `__defaults__` &
> > > `__kwdefaults__`, instead of `Ellipsis`).
> >
> > Ah, I guess you didn't see .extra then. Currently the only possible
> > meanings for extra are None and a string, and neither has meaning
> > unless the default is Ellipsis; it's possible that, in the future,
> > other alternate defaults will be implemented, which is why I 

[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread 2QdxY4RzWzUUiLuE
On 2021-12-12 at 17:28:23 +1300,
Greg Ewing  wrote:

> On 11/12/21 1:22 pm, Christopher Barker wrote:
> > Darn — the P and A are swapped there.
> 
> "Argument" and "actual" both start with "A" -- does that help?

Then Parameters must be Potential (before they become Actualized as
Arguments)?
___
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/2T3NHAA3D5JKWTJRCEZWCWPCRVSKD6W3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: inline Python functions and methods

2021-12-11 Thread Greg Ewing

On 11/12/21 5:40 pm, TobiasHT wrote:

> The right function to perform inlining on shall be determined at runtime and 
cached in the same scope as where it’s performing it’s operations from cases where 
the program performs large iterations or even in infinite loops and other cases 
that need optimization.


If it's to be a run-time optimisation, you could consider dropping
the inline declaration and just have the implementation decide
whether it's worth inlining things, based on factors such as the
size of the function and how often it's called.

Then the language wouldn't have to be changed at all, and programmers
wouldn't need to have foresight to decide when to declare things
inline.

--
Greg
___
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/UXKJ4JA42IGZXN6CITX2USZKJ3FGOTRH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Greg Ewing

On 11/12/21 1:22 pm, Christopher Barker wrote:

Darn — the P and A are swapped there.


"Argument" and "actual" both start with "A" -- does that help?

--
Greg
___
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/6XS45CV4GJHYGMEAHKLTBKXEFFDSK3TX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Stephen J. Turnbull
Chris Angelico writes:

 > So [a "deferred object" is] a lambda function that gets called the
 > moment you touch it in any way.

I'll take that as a question, though you present it like a fact.  It's
a code object plus "other stuff" that gets called automatically when
dereferencing a name in most contexts (like a descriptor but works
with "plain" identifiers rather than attribute names).  Other cases
I'm not sure about, and I don't know whether they can be resolved in a
way *generally* useful enough to make them worth adding.  For example,
let a and b[0] both refer to a "deferred object".

1.  The statement x = a will evaluate the contained expression.
2.  I don't know when x = b[0] will evaluate the contained expression.
3.  I don't know when f(a) will evaluate the contained expression.
4.  There will be APIs such as "isdeferred(x)" and "unevalled x" that
do not evaluate the contained expression.

I think my answers are "2. before binding x" and "3. as in PEP 671",
but I'm somewhat unsure of both, since I don't know David's and Eric's
use cases.  (FWIW, the alternatives I had in mind were "2. when x is
dereferenced" and "3. when a is dereferenced in the body of f".  There
may be others.)

The "other stuff" mentioned above similarly depends on use cases that
I don't know.  I suspect that "use cases I don't know" are
characteristic of everyone's reluctance to do a "generic deferred
evaluation" PEP.  I get the feeling there are a number of them.

 > >  > (Another theoretical difference is that a deferred expression is
 > >  > parsed in the context of its *usage* rather than its *definition*, but
 > >  > that would break all manner of things in Python and is quite
 > >  > impractical.)
 > >
 > > I'm a little confused by "theoretical" and "parsed".
 > 
 > What I mean is that I don't know whether you intend it one way or the
 > other, so I don't know whether it's an actual difference in your
 > proposal, or something that could in theory be.

Do you not realize that "you" is plural, and "proposal" is not unique
at this point?  In particular, I was asking about you channelling
Eric.  I was not making any statement about my own proposal (which is
starting to gel but until a day or so ago was 100% nonexistent), or
Eric's for that matter.

I still don't understand why time of parsing matters.  Do you mean
time of compilation?

 > If name lookups in these temporary expressions have to refer to
 > names in the target function, not in their current context, it
 > causes all kinds of problems.

That's what Ruby blocks do, and Rubyists love them.  They certainly
don't think blocks have huge problems.

Alternatively, it would certainly be possible to do as Common Lisp
does, and provide for optional closure over creation-time arguments as
well as access to namespaces active at evaluation time via explicit
APIs.  Sure, all this would be complex, and maybe "too complicated to
be a good idea".  On the other hand, there may be other use cases that
can take advantage of evaluation of a simple reference to z after
z = defer foo(*args) besides the case of late binding of function 
arguments.  If those use cases are sufficiently compatible and
compelling, it may be possible to define the implicit APIs and add
explicit APIs as needed in the future.

 > Is that your intention?  Otherwise, what is x there?

I don't understand why you are pushing so hard for these details, when
I doubt any of the advocates of a more general deferred evaluation
facility have communicated with each other yet, and the details
probably vary substantially.  And even David has acknowledged that he
doesn't have a worked-out proposal at the moment, only a wisp of a
threat to write one.

It's reasonable to say, as you have, "my proposal is the only one on
the table."  That's true (and acknowledged by all who prefer to wait
for a generic deferred evaluation proposal), but existence of a
proposal is a necessary condition for adoption, not sufficient.  If
nonexistence of a competing proposal is not the point you're trying to
make, I'm not sure what you're after in this subthread.

Please don't waste your time answering any implicit questions in this
post.  If you find them interesting, go right ahead, but I'm not
asking for answers from you, I'm trying to provide answers to your
questions as I understand them.  (David, Eric, and any lurkers may
have different answers, though!)

Regards,
Steve

___
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/TQVLHXENCFAMQCCBLC2KIUFUPU5PMEGU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Steven D'Aprano
On Sat, Dec 11, 2021 at 05:02:39PM -0800, Christopher Barker wrote:
> On Sat, Dec 11, 2021 at 3:03 PM Steven D'Aprano  wrote:

> > Didn't we decide there was an existing feature for this, no need for
> > new syntax?

> Well, no. In fact, you could always put anything you wanted into an
> annotation:

Right, and we want to put a documentation string in it! :-)


> Anyway, take a look at the docs for Annotated:
> 
> https://docs.python.org/3/library/typing.html#typing.Annotated
> 
> It has a number of possible unspecified uses, but fundamentally, it's about
> the adding information to the type, not to the attribute -- e.g. not really
> intended for docstrings.

I don't think that the docs argue against this. Annotated is documented 
as the way to put arbitrary metadata into an annotation. What you do 
with it is up to the consumer of the metadata.

The docs talk about this associating the metadata with the type, but 
that's because this is the *typing* module and *type* hints are still 
the primary use-case for annotations.

And despite what the docs say, the metadata is actually, literally, 
associated with the variable (or its name at least). The annotation that 
gets stored in __annotations__ is **not**

{T: "metadata"}

as a naive reading of the docs might trick you into believing, but

{"var": Annotated[T, "metadata"]}


In any case, we can still use annotations for anything we like, and 
while typing is definitely and certainly the primary use for them, there 
will always be a way to opt-out. (Just don't run mypy!)

Don't need type hints at all? Great, put your doc string as the 
annotation.

μ: 'Number of steps from x0 to the start of the cycle.'
λ: 'Length (period) of the cycle.'
y: 'Value of f at the start of the cycle.' = None

You might want to annotate the class with `no_type_check` if there is 
any chance the user might want to run mypy over your module, but that's 
entirely up to you.

You do want type hints? Great, use Annotated. If there's an attribute 
that you don't want to give a type hint to, just use Any. (A small price 
to pay for using an existing feature, instead of waiting until Python 
3.11 or 3.27 when it gets added to the core language.)

μ: Annotated[int,
 'Number of steps from x0 to the start of the cycle.']
λ: Annotated[int, 'Length (period) of the cycle.']
y: Annotated[Any, 
 'Value of f at the start of the cycle.'
 ] = None

No new syntax required. No bare strings floating around. You can 
generate the doc strings dynamically, they don't have to be literals.

lunch: Annotated[Meal, ' '.join(['spam']*SPAM_COUNT)]


> Sure, typing.Annotated *could* be used that way, but I don't think we can
> say that the problem is solved.

I think that from a language standpoint, we absolutely can say that the 
problem is solved. We don't need new syntax.

We *might* want to standardise on a decorator or other tool to extract 
those docstrings, possibly sticking them in a new __attrdoc__ dunder. 
Being a dunder, we should get the core dev's approval for this, even if 
it is a third-party tool that uses it.

(I assume we don't already use __attrdoc__ for something?)

If the first use of this is dataclasses, then that would be de facto 
core dev approval.

So we have a tool that takes an annotation:

var: Annotated[T, docstring, *args]

extracts out the docstring to an __attrdoc__ dunder:

# Class.__attrdoc__
{'var': docstring}

and removes the annotation from the annotation:

# Class.__annotation__
{'var': Annotated[T, *args]}  # or just T if *args is empty?

Dataclasses can automatically apply this tool (subject to backwards 
compatibility constraints), or we can apply it as a decorator to any 
other class we want.

So we've gone from the *hard* problem of making a language change (new 
syntax, build the functionality into the interpreter) to the *easy* 
problem of writing a decorator.


> Heck you could just as easily provide a tuple for the annotation:
> 
> In [17]: class C:
> ...: x: ("Doc string", int) = 123
> ...:


Sure, annotations can be anything you like. But external static typing 
tools may not support this, and will be confused or break. Same for 
third-party runtime tools.

Best practice is to stick as closely to the standard type-hinting 
behaviour as you can, or to completely opt-out with no_type_hints.


> The use cases for annotations are a bit up in the air at the moment -- see
> the ongoing discussion on python-dev. But I don't think there's any doubt
> that any future endorsed use of them will be compatible with static typing
> (if not restricted to it), so extending the use of annotations for
> docstrings would take a bit of work to define and accept that use.

Annotated is explicitly documented as *arbitrary* metadata that is 
entirely up to the application to interpret. There's no reason to think 
that will change.


> Perhaps a better way to do that than 

[Python-ideas] Re: Make it easier to set function globals

2021-12-11 Thread Chris Angelico
On Sun, Dec 12, 2021 at 1:23 PM Steven D'Aprano  wrote:
>
> TL;DR: it is hard, but not impossible, to set function `__globals__`
> dunder to a ChainMap. Let's make it easier!
>
> Attempt 1: set __globals__ directly.
>
> >>> func.__globals__ = ns
> Traceback (most recent call last):
>   File "", line 1, in 
> AttributeError: readonly attribute
>
> I think we should have:
>
> - allow func.__globals__ to be writable;

CodeType has a replace() method that returns a new code object with
identical attributes but for the ones you asked to change. If making
__globals__ writable causes problems, a FunctionType.replace() method
would probably be a good alternative.

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/EQ5LEXW7IU24UVDJ3XHC4SEXYCZFK5CM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Make it easier to set function globals

2021-12-11 Thread Steven D'Aprano
TL;DR: it is hard, but not impossible, to set function `__globals__` 
dunder to a ChainMap. Let's make it easier!


Background:

(1) Comprehensions skip class scope, leading to bug reports like these:

https://bugs.python.org/issue3692
https://bugs.python.org/issue26951

Note Guido's comment in the first:

"perhaps __globals__ could be set to a chainmap referencing the class 
dict and the globals?"


(2) I want to experiment with namespaces, similar to the C++ feature. 
The details don't matter, but one way I can do that experiment is to use 
a class and ChainMap.

So let's try an experiment: set up a namespace using ChainMap, and try 
to monkey-patch a function to use it instead of the regular globals.

Here is my setup code:

def func():
return (a, b, c)

a = b = c = "global"
from collections import ChainMap
ns = ChainMap({'a': 'CM-0'}, {'b': 'CM-1'}, globals())

Let's see what it takes to set func.__globals__ to ns.


Attempt 1: set __globals__ directly.

>>> func.__globals__ = ns
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: readonly attribute



Attempt 2: use the FunctionType constructor.


>>> from types import FunctionType
>>> f = FunctionType(func.__code__, globals=ns)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: function() argument 'globals' must be dict, not ChainMap


Attempt 3: fool the constructor.

>>> class MyChainMap(ChainMap, dict):
... pass
...
>>> ns = MyChainMap({'a': 'CM-0'}, {'b': 'CM-1'}, globals())
>>> f = FunctionType(func.__code__, globals=ns)

Success!

And now the function behaves as desired:

>>> f()
('CM-0', 'CM-1', 'global')

This was too hard! What can we do to make it easier?

I think we should have:

- allow func.__globals__ to be writable;

- allow anything that inherits from the Mapping ABC.


Thoughts?



-- 
Steve
___
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/5AUFO6NMDR5XABYCEU2LKXVDBQDXORUT/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Paul Bryan
On Sat, 2021-12-11 at 17:02 -0800, Christopher Barker wrote:

> It [Annotated] has a number of possible unspecified uses, but
> fundamentally, it's about the adding information to the type, not to
> the attribute -- e.g. not really intended for docstrings.

Ah, good point. I've conflated the two because dataclass attributes are
used to define the schema of the dataclass. For general purpose
attribute docstrings (module, class), I agree Annotated is probably
inappropriate. 

> Perhaps a better way to do that than to use Annotated would be to
> introduce new "thing", maybe in teh typoing module, like
> "Documented":

I think this will suffer from the same problem as Annotated: it would
document the type, not the attribute itself.

> Anyway, what I'm getting at is that it needs to be determined whare
> to put the docstrings before we can get very far with this idea.

How is Sphinx is pulling the string below the attribute? Whatever
mechanism is to be used, I propose it must allow for runtime
introspection.

___
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/LG7NQUZ67XTVXUAEXRTNHTXFXIH4NDYC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Christopher Barker
On Sat, Dec 11, 2021 at 3:03 PM Steven D'Aprano  wrote:

> On Sat, Dec 11, 2021 at 10:07:50AM -0800, Christopher Barker wrote:
> > Where/how should class attribute doc strings be stored?
> >
> > Tacked on to the class __doc__ ?
> > Another dict?
> > __attr_doc__
> > Added to __annotaions__ ?
> > Something else?
>
> Didn't we decide there was an existing feature for this, no need for
> new syntax?
>
> >>> from typing import Annotated
> >>> class C:
> ... x: Annotated[int, "Doc string"] = 123
> ...
> >>> C.x
> 123
> >>> C.__annotations__
> {'x': typing.Annotated[int, 'Doc string']}
>

Well, no. In fact, you could always put anything you wanted into an
annotation:

In [10]: class C2:
...: x: "a docstring" = 123
...:

In [11]: inspect.get_annotations(C2)
Out[11]: {'x': 'a docstring'}

So the typing module contains a nifty thing they've called "Annotatated",
and, I imagine type checkers (like MyPy) do something sensible with them,
but there's nothing else going on here. Actually yes, there is, the
typing,get_type_hints function strips out the annotation:

In [13]: class C:
...: x: Annotated[int, "Doc string"] = 123
...:

In [14]: typing.get_type_hints(C)
Out[14]: {'x': int}

Anyway, take a look at the docs for Annotated:

https://docs.python.org/3/library/typing.html#typing.Annotated

It has a number of possible unspecified uses, but fundamentally, it's about
the adding information to the type, not to the attribute -- e.g. not really
intended for docstrings.

Sure, typing.Annotated *could* be used that way, but I don't think we can
say that the problem is solved.

Heck you could just as easily provide a tuple for the annotation:

In [17]: class C:
...: x: ("Doc string", int) = 123
...:

In [18]: inspect.get_annotations(C)
Out[18]: {'x': ('Doc string', int)}

The use cases for annotations are a bit up in the air at the moment -- see
the ongoing discussion on python-dev. But I don't think there's any doubt
that any future endorsed use of them will be compatible with static typing
(if not restricted to it), so extending the use of annotations for
docstrings would take a bit of work to define and accept that use.

Perhaps a better way to do that than to use Annotated would be to introduce
new "thing", maybe in teh typoing module, like "Documented":

class C:
x: Documented(doc_string="this is the doc string", type=int) = 123

and then inspect.get_annotations and typing,get_type_hints could be taught
to extract the type from the Documented object, and we could add an
inspect.get_docstrings() function, so that:

typing.get_type_hints(C)
{'x': int}

inspect.get_docstrings(C)
{'x': 'this is the doc string'}

And, of course, future syntax could automatically create a Documented()
object if there was a docstring in the appropriate place.

Or just have a new dunder for it, e.g. __attr_doc__

Anyway, what I'm getting at is that it needs to be determined whare to put
the docstrings before we can get very far with this idea.

-CHB











>
> --
> Steve
> ___
> 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/UQV3GZLVHDCHXKN4L2QCIHYLFTWBFEW3/
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
Christopher Barker, PhD (Chris)

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
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/LEFJD7BVN43E4EUNZOKTT2M7YOYU262R/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Christopher Barker
On Sat, Dec 11, 2021 at 10:49 AM Ricky Teachey  wrote:

> The __annotations__ already exists. Is that a point in favor?
>

Yes and no. Right now, any object can be stored in annotations — having a
docstring tacked on would break who knows how much code.

However, there is the new inspect.get_annotations function, which could be
adapted to process doc strings.

https://docs.python.org/3/howto/annotations.html

If the syntax could become sugar for creating an Annotated object in
> __annotations__, this would be a pretty convenient location to find them.
>
> On the other hand, not every type hinted variable will have a docstring.
>

And not every attribute with a docstring would have an annotation.

 It seems like storing them in a so called __attr_doc__ might be the most
> straightforward thing to do.
>

Yes, as doc strings really are a different thing.

Though one might to also document other things like function parameters—
which would be an argument for extending what __annotations__ is used for.

If that were done, does it matter that the contents of __attr_doc__ and
> __annotations__ are not coupled?
>

I don’t think so — they are quite different concepts.

-CHB


-- 
Christopher Barker, PhD (Chris)

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
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/OTIC243UANQAVFSI3JAHQZATFRDKT7KJ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Paul Bryan
I think that because Sphinx could interpret strings below attributes
for documentation, that perhaps we should go in that direction in
Python proper.

Personally, I find this more readable:

  class C:
x: Annotated[str, "Doc string"]
    y: Annotated[int, "Doc string"]

over:

  class C:
x: str
    "Doc string"
y: int
"Doc string"


On Sun, 2021-12-12 at 10:00 +1100, Steven D'Aprano wrote:
> On Sat, Dec 11, 2021 at 10:07:50AM -0800, Christopher Barker wrote:
> 
> > Where/how should class attribute doc strings be stored?
> > 
> > Tacked on to the class __doc__ ?
> > Another dict?
> > __attr_doc__
> > Added to __annotaions__ ?
> > Something else?
> 
> Didn't we decide there was an existing feature for this, no need for 
> new syntax?
> 
> > > > from typing import Annotated
> > > > class C:
> ... x: Annotated[int, "Doc string"] = 123
> ... 
> > > > C.x
> 123
> > > > C.__annotations__
> {'x': typing.Annotated[int, 'Doc string']}
> 
> 

___
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/MEFYE3FPMI7L4QPO4PRJ424IJ3HPXFEN/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Steven D'Aprano
On Sat, Dec 11, 2021 at 10:07:50AM -0800, Christopher Barker wrote:

> Where/how should class attribute doc strings be stored?
> 
> Tacked on to the class __doc__ ?
> Another dict?
> __attr_doc__
> Added to __annotaions__ ?
> Something else?

Didn't we decide there was an existing feature for this, no need for 
new syntax?

>>> from typing import Annotated
>>> class C:
... x: Annotated[int, "Doc string"] = 123
... 
>>> C.x
123
>>> C.__annotations__
{'x': typing.Annotated[int, 'Doc string']}


-- 
Steve
___
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/UQV3GZLVHDCHXKN4L2QCIHYLFTWBFEW3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Ricky Teachey
On Sat, Dec 11, 2021, 1:19 PM Christopher Barker 
wrote:

> 
>
> Where/how should class attribute doc strings be stored?
>
> Tacked on to the class __doc__ ?
>
> Another dict?
>
> __attr_doc__
>
> Added to __annotaions__ ?
>
> Something else?
>
> If they are to be available at run time, they need to go somewhere…
>
> -CHB
>
>>
>> --
> Christopher Barker, PhD (Chris)
>

The __annotations__ already exists. Is that a point in favor? If the syntax
could become sugar for creating an Annotated object in __annotations__,
this would be a pretty convenient location to find them.

On the other hand, not every type hinted variable will have a docstring. It
might be inconvenient to have them there only. It seems like storing them
in a so called __attr_doc__ might be the most straightforward thing to do.

If that were done, does it matter that the contents of __attr_doc__ and
__annotations__ are not coupled? The strings might need to be modified.
Would be inconvenient to have to modify two places in such a situation.
___
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/7S4RM4APDP4FC7L6DBHJU7GAHES3ABPV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Ricky Teachey
On Sat, Dec 11, 2021, 12:57 AM Stephen J. Turnbull <
stephenjturnb...@gmail.com> wrote:

Simão Afonso writes:
 > On 2021-12-10 12:20:44, Ricky Teachey wrote:
 > > I meant to ask about a (global) module member, not the module docstring
 > > itself. Like MY_GLOBAL below:
 > >
 > >  """This is the module docs"""
 > >
 > >  MY_GLOBAL = None
 > >  """MY_GLOBAL docs"""
 > >
 > > Is this "global docstring" recognized by Sphinx as a docstring, too?
 >
 > My bad.
 >
 > Double checked and that's right, it is recognised as such.

To my mind Sphinx is sufficiently widely used that this settles the
"above or below" question.

Steve


I agree.

Even with this convention one could still accomplish separating the
documentation section from the definition section, like:

class Steel:
"""A simple material model of steel."""

# parameters
E_s: float
"the linear elastic modulus"

nu: float
"the poisson's ratio"

gamma: float
"the density"

# values
E_s = 29e6  # ksi
nu = 0.3
gamma = 490  # lbs per cu ft

As has already been observed, we already have something LIKE an attribute
docstring, which is an Annotated type hint object.

Should the bare docstring below the member become sugar for creating an
Annotated type hint?

x = 1
"spam"

Would then be equivalent to:

x: typing.Annotated[typing.Any, "spam"]

This seems really nice to me.
___
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/LO7KDBDFKKDI5XJJ7GE227PBTTM3D7NN/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Runtime-accessible attribute docstrings – take 2

2021-12-11 Thread Christopher Barker
On Fri, Dec 10, 2021 at 9:57 PM Stephen J. Turnbull <
stephenjturnb...@gmail.com> wrote:

> To my mind Sphinx is sufficiently widely used


And the system used for the official Python docs.

that this settles the
> "above or below" question.


So yes :-)

However, what I haven’t seen in this thread is discussion of what I think
is the key question:

Where/how should class attribute doc strings be stored?

Tacked on to the class __doc__ ?

Another dict?

__attr_doc__

Added to __annotaions__ ?

Something else?

If they are to be available at run time, they need to go somewhere…

-CHB

>
> --
Christopher Barker, PhD (Chris)

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
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/RWTU2EJ2TIC62IU2WZZUPO3CEPLRLTRY/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Eric V. Smith

On 12/11/2021 12:11 PM, Chris Angelico wrote:

On Sun, Dec 12, 2021 at 4:06 AM Christopher Barker  wrote:

Here’s a new (not well thought out) idea:

@dataclasses.dataclass
class A:
 Input_list: list
 length: int => len(input_list)

So length gets set to a “late bound default expression” that Is an actual 
value. It would have to store the expression itself, probably as a string, and 
it would get evaluated in the namespace of the function, when the function was 
called. So the generated __init__ would be the same as:

def __init__(self, input_list, length=>len(input_list):

If I'm not mistaken, dataclasses generate __init__ using exec anyway,
so this would work with a plain string.


The current version does, but I've produced previous versions that 
don't. They built up the AST themselves and use eval() on that.


Eric

___
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/FPKXOT6T4H36YC5QIKSJXEASIHTM7IES/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Chris Angelico
On Sun, Dec 12, 2021 at 4:06 AM Christopher Barker  wrote:
> Here’s a new (not well thought out) idea:
>
> @dataclasses.dataclass
> class A:
> Input_list: list
> length: int => len(input_list)
>
> So length gets set to a “late bound default expression” that Is an actual 
> value. It would have to store the expression itself, probably as a string, 
> and it would get evaluated in the namespace of the function, when the 
> function was called. So the generated __init__ would be the same as:
>
> def __init__(self, input_list, length=>len(input_list):

If I'm not mistaken, dataclasses generate __init__ using exec anyway,
so this would work with a plain string.

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/26KTI6DXSB5GJBXEHHFXZEW3222NVWWK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Christopher Barker
On Fri, Dec 10, 2021 at 7:54 PM Eric V. Smith  wrote:

> Not sure if you meant this to go to the list or not.
>
I did — ( I know it seems to be the consensus, but I really think respond
to list should be the default…)

Moving on…

On 12/10/2021 7:50 PM, Christopher Barker wrote:
>
> Thanks Eric, this is a great example, thanks.
>
> It does raise some questions. Though.
>
> If we could use any expression as a deferred expression, then we still
> have the two key questions:
>
> When does it get evaluated, and what namespaces does it use?
>
> I agree those are good questions. I think, like PEP 671, it would get
> evaluated at the start of the function (in this case, __init__). It's
> easier for dataclasses, because I could just force the evaluation there.
> But for normal function arguments, maybe we'd have to say that before the
> function starts executing, any arguments which are deferred objects
> automatically are evaluated. And I think the namespace would be where it's
> defined.
>
Ahh, then that would make them less useful for default parameters— even for
the dataclass case. It would work fine if you used only builtins (or
literals) but that’s about it. So Chris’ canonical example of n =>
len(input_list) wouldn’t work.

Which is why I think that if there were a general purpose deferred object,
we’d need special syntax or rules for when used as late-bound defaults.

I'll admit I haven't thought all of this through in enough detail to
> implement it. I'm just trying to point out that we could use the general
> concept in other places.
>
Which is exactly what I asked for — thanks! I think this is a really
interesting use case, not so much as it’s a general purpose deferred
object, but because it’s about how to do/use late-bound defaults in meta
programming.


> def fun(n):
> return `len(n)`
>
> @dataclasses.dataclass
> class A:
> length: n = fun()
>
> What would that put in the signature? What namespace would the express e
> evaluated in?
>
> I think it should be evaluated in the context of "fun". Clearly it would
> need to create a closure.
>

Which would be a potentially useful deferred object, but not a good one for
late-bound defaults.

Here’s a new (not well thought out) idea:

@dataclasses.dataclass
class A:
Input_list: list
length: int => len(input_list)

So length gets set to a “late bound default expression” that Is an actual
value. It would have to store the expression itself, probably as a string,
and it would get evaluated in the namespace of the function, when the
function was called. So the generated __init__ would be the same as:

def __init__(self, input_list, length=>len(input_list):

And you could also do:

get_length => len(input_list)

@dataclasses.dataclass
class A:
Input_list: list
length: int = get_length

Not that that would be a good idea.

This suggestion would mean that “=>” would create a deferred expression,
but it would not be a general purpose one.

Though maybe there could be a way to evaluate it in a more general way,
kind of like eval — where you can control the namespaces used.

I guess what I’m suggesting is that we could create a very specific kind of
deferred object, and in the future expand it to more general use. Rather
than the general case rendering the late-bound default concept.

-CHB

> --
Christopher Barker, PhD (Chris)

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
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/7PYISXVUZMK2A7VUPNYU4Q2QD6JJEEUC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Python standard library TOML module

2021-12-11 Thread Pradyun Gedam
The line of reasoning for the packaging tooling choosing TOML is elaborated 
upon in PEP 518 (https://www.python.org/dev/peps/pep-0518/#other-file-formats) 
and that choice was informed by a survey of the existing formats: 
https://gist.github.com/njsmith/78f68204c5d969f8c8bc645ef77d4a8f.
___
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/SDAJ4DCK7GJIMEONNYJ3NNXKJYGQWJDF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Eric V. Smith

And my response again, although slightly edited.

On 12/11/2021 11:28 AM, Christopher Barker wrote:

Sorry, accidentally off-list. Here it is again.

On Fri, Dec 10, 2021 at 4:50 PM Christopher Barker 
 wrote:


Thanks Eric, this is a great example, thanks.

It does raise some questions. Though.

If we could use any expression as a deferred expression, then we
still have the two key questions:

When does it get evaluated, and what namespaces does it use?

I agree those are good questions. I think, like PEP 671, it would get 
evaluated at the start of the function (in this case, __init__). It's 
easier for dataclasses, because I could just force the evaluation there. 
But for normal function arguments, maybe we'd have to say that before 
the function starts executing, any arguments which are deferred objects 
automatically are evaluated. And I think the namespace would be where 
it's defined. I'll admit I haven't thought all of this through in enough 
detail to implement it. I'm just trying to point out that we could use 
the general concept in other places.


One thing in particular I haven't thought through: what if you really 
want to pass in a "deferred object" to a function? Can you keep it from 
being evaluated? Would you specify that on the caller side, or the 
callee side?





@dataclasses.dataclass
class A:
    my_list: list = dataclasses.field(default_factory=list)

What I'd like to be able to say:

@dataclasses.dataclass
class A:
    my_list: list = `[]`


I think in the data classes case, you could clearly define both of
those. But in the general case?

def fun(n):
    return `len(n)`

@dataclasses.dataclass
class A:
  length: n = fun()

What would that put in the signature? What namespace would the
express e evaluated in?

I think it should be evaluated in the context of "fun". Clearly it would 
need to create a closure.



Yes, that is completely contrived, but it does bring up the
complications of a “general” solution.

Maybe we could solve the dataclass problem with late bound class
attributes:

@dataclasses.dataclass
class A:
    length: n => len(n)

Though I suppose that would still get evaluated before the
dataclass decorator would see it :-(

There are absolutely some issues that need thinking through. It's 
entirely possible the idea can't be made to work. I'm just saying we 
should think it through and see if it could be made to work before we 
just say "we only want late-bound things as function parameters, and we 
can't use them anywhere else". I'm worried that if we only do it for 
function parameters, we might need to change the syntax (and I guess 
possibly the semantics) in the future in order to support other uses for 
deferred objects.



Side note: I wonder if dataclasses could be a bit smarter for the
common. case: if the type is a callable, and the value is a
particular Sentinel, the. Call it to get the default:

@dataclasses.dataclass
class A:
    my_list: list = dataclasses.Empty

That would work for most of the cases where I need to use field
explicitly.


That's an interesting idea.

Eric



- CHB





In the class A, before @dataclass is called, I want A.my_list
to be a "deferred object" that I could then use when
@dataclass is generating __init__(). Exactly how and when the
"deferred object" would get evaluated is debatable, but not
so important for the sake of this discussion. Suffice it to
say that it would either be explicitly or implicitly
evaluated at the start of __init__.

I think you can see that this would benefit from similar
functionality to late-bound parameters, and that if we had
this more general mechanism that late-bound parameters could
use the same underlying mechanism.


And in case I wasn't clear: to get the late-bound parameter
functionality using this syntax, you'd use:

def foo(my_list = `[]`):

That's why I think we should have a larger concept that just
late-bound parameters: I think there's a general concept here
that can be extended beyond parameters. And that's why I thing
not restricting it to a function-definition-only syntax is
important: we should produce a syntax that can be used in more
places than just functions. This is why I think we need to
decide on this larger scope before accepting the narrow
function-definition-only syntax: if we decide to add "deferred
objects" later, we'd have two ways to specify late-bound
parameters [0].

Eric

[0]: Or arguments, I can never remember which is which:
someone needs to invent a memorable mnemonic device.


Had these "deferred objects" existed when I designed
dataclasses, I would 

[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Christopher Barker
Sorry, accidentally off-list. Here it is again.

On Fri, Dec 10, 2021 at 4:50 PM Christopher Barker 
wrote:

> Thanks Eric, this is a great example, thanks.
>
> It does raise some questions. Though.
>
> If we could use any expression as a deferred expression, then we still
> have the two key questions:
>
> When does it get evaluated, and what namespaces does it use?
>
> @dataclasses.dataclass
>> class A:
>> my_list: list = dataclasses.field(default_factory=list)
>>
>> What I'd like to be able to say:
>>
>> @dataclasses.dataclass
>> class A:
>> my_list: list = `[]`
>>
>> I think in the data classes case, you could clearly define both of those.
> But in the general case?
>
> def fun(n):
> return `len(n)`
>
> @dataclasses.dataclass
> class A:
> length: n = fun()
>
> What would that put in the signature? What namespace would the express e
> evaluated in?
>
> Yes, that is completely contrived, but it does bring up the complications
> of a “general” solution.
>
> Maybe we could solve the dataclass problem with late bound class
> attributes:
>
> @dataclasses.dataclass
> class A:
> length: n => len(n)
>
> Though I suppose that would still get evaluated before the dataclass
> decorator would see it :-(
>
> Side note: I wonder if dataclasses could be a bit smarter for the common.
> case: if the type is a callable, and the value is a particular Sentinel,
> the. Call it to get the default:
>
> @dataclasses.dataclass
> class A:
> my_list: list = dataclasses.Empty
>
> That would work for most of the cases where I need to use field explicitly.
>
> - CHB
>
>
>
>
> In the class A, before @dataclass is called, I want A.my_list to be a
>> "deferred object" that I could then use when @dataclass is generating
>> __init__(). Exactly how and when the "deferred object" would get evaluated
>> is debatable, but not so important for the sake of this discussion. Suffice
>> it to say that it would either be explicitly or implicitly evaluated at the
>> start of __init__.
>>
>> I think you can see that this would benefit from similar functionality to
>> late-bound parameters, and that if we had this more general mechanism that
>> late-bound parameters could use the same underlying mechanism.
>>
>> And in case I wasn't clear: to get the late-bound parameter functionality
>> using this syntax, you'd use:
>>
>> def foo(my_list = `[]`):
>>
>> That's why I think we should have a larger concept that just late-bound
>> parameters: I think there's a general concept here that can be extended
>> beyond parameters. And that's why I thing not restricting it to a
>> function-definition-only syntax is important: we should produce a syntax
>> that can be used in more places than just functions. This is why I think we
>> need to decide on this larger scope before accepting the narrow
>> function-definition-only syntax: if we decide to add "deferred objects"
>> later, we'd have two ways to specify late-bound parameters [0].
>>
>> Eric
>>
>> [0]: Or arguments, I can never remember which is which: someone needs to
>> invent a memorable mnemonic device.
>>
>> Had these "deferred objects" existed when I designed dataclasses, I would
>> have used them instead of the clunky default_factory. PEP 671 does not help
>> with this use case, where a late-bound parameter isn't specified in a
>> function definition. I need the late-bound parameter to be stored in an
>> object I can refer to later.
>>
>> Eric
>>
>> ___
>> 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/T62V6IMOJDADAFWJ2DIAS4WHJQMI4CHU/
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
> --
> Christopher Barker, PhD (Chris)
>
> Python Language Consulting
>   - Teaching
>   - Scientific Software Development
>   - Desktop GUI and Web Development
>   - wxPython, numpy, scipy, Cython
>
-- 
Christopher Barker, PhD (Chris)

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
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/IDKDVY4LNNB2WLQVS6QM3OZX6C6QXE7Y/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Python standard library TOML module

2021-12-11 Thread Finn Mason
Yes!! This is something I've thought about proposing for a while, but I was
too lazy to do it. TOML is a wonderful language with an important place in
the Python ecosystem.


--
Finn (Mobile)

On Fri, Dec 10, 2021, 9:57 AM Sebastian Koslowski <
sebastian.koslow...@gmail.com> wrote:

> There is already some info/discussion over on the bug tracker:
>
> https://bugs.python.org/issue40059
>
> Sebastian
> ___
> 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/ZQOD6TEOWAB47WL2IMQS2W67IAKS46NR/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
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/YNA3NQDQEUY56M54INRQHJCYD44I4SI7/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Chris Angelico
On Sat, Dec 11, 2021 at 8:07 PM Stephen J. Turnbull
 wrote:
>
> Chris Angelico writes:
>  > On Sat, Dec 11, 2021 at 5:35 PM Stephen J. Turnbull
>  >  wrote:
>
>  > > foo(x=>[a])
>
>  > I'm not sure what that last line would mean.
>
> This isn't about your proposal, it's about more general syntax.  Not
> everything being discussed is about your proposal, and I suspect one
> reason you have trouble figuring out what other people are talking
> about is that you persistently try to force everything into that
> context.

Yes, it's silly of me to think of everything in a PEP 671 thread as if
it's about argument defaults. Carrying on.

The reason I thought it might be about arg defaults is that you did
also show an arg default in the exact same block. That kinda sullies
the waters a bit. Actually, a lot. If you want to talk about deferred
expressions, can you restrict it to one example rather than two? It's
hard to parse, especially with all the one-letter names.

>  > My proposal doesn't change the call site in any way, so I'm trying
>  > to figure out what you mean by that call. Are you saying that
>  > x=>[a] would be an assignment statement that sets x to an
>  > unevaluated expression?
>
> No, I'm saying it would be an assignment expression (like :=), but
> that's what it would do.  But that binding would be ignored, and the
> value passed into the function in the usual way.  A keyword argument
> would be set with the even uglier x = (x=>[a]).

uhhh I'm lost. Are you saying that "x=>" is a magic token that
doesn't actually assign to x, but it just means that the thing that
follows it is a deferred expression? If so, why not a keyword like
"defer"?

>  > It would also require significant changes to the way that nonlocal
>  > names are looked up (or would be restricted in what nonlocals it
>  > can refer to, possibly none at all).
>
> All of which should clue you in that that's probably not what I'm
> talking about, especially when I explicitly wrote "while in an
> executable context, it could return the object, as := does".

What's an executable context though? I don't understand.

>  > Indeed. But here's the question: If a deferred object is to be a
>  > replacement for default_factory, then it must by definition be able to
>  > be stored for later. So it can't be autoevaluated unless there's some
>  > mechanism for delaying the autoevaluation. This seems like an
>  > incredibly messy approach.
>
> Such an object is not evaluated when created; it's evaluated when
> referenced, like a descriptor.  Descriptors are messy, too, but
> very useful.

How?

>  > What would have overlap with argument defaults isn't the same thing
>  > that would be useful for dataclasses.
>
> If you say so, but forgive me if I table your comment and wait for
> Eric to weigh in on requirements related to dataclasses.  In any case,
> if the default is such a deferred object x, I'm pretty sure that doing
> x=x before entering the function body is equivalent to your proposal.
> I see no particular reason why we couldn't have that rule for
> "deferred objects" created in "function signature scope".

I *really* don't like that idea. If you want to propose that kind of
thing, where it magically changes when you look at it, then go ahead,
but that has nothing whatsoever to do with PEP 671, as it doesn't
answer the same use-cases, is largely orthogonal, can be better
explained without argument defaults being involved at all, and happens
at the call site rather than the function signature. If I'm
understanding your proposal correctly, using one of these deferreds as
an argument default would look like "def f(x=x=>[]):", which, as well
as being weirdly ugly, wouldn't even be incompatible with the proposal
I'm making.

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/LK5VSKOLSEH5N6JI2IVZSCNQH53E4UJF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Chris Angelico
On Sat, Dec 11, 2021 at 8:07 PM Stephen J. Turnbull
 wrote:
>
> Chris Angelico writes:
>
>  > It's larger than argument defaults, but also smaller:
>
> Aside: I'm quite confused by your whole line of discussion here, but
> I'll let Eric follow up.
>
>  > The overlap with late-bound defaults is the simple case of mutable
>  > objects that you want to freshly construct every time, but
>  > ultimately, that's not hugely different from a lambda function:
>
> Of course it's hugely different from a lambda function.  It will be
> evaluated at the time of reference, whereas a lambda function will
> not, it won't be evaluated until called.  (This means that to access a
> deferred object without evaluating it, a separate API will be needed,
> sort of the dual of function call.)

So it's a lambda function that gets called the moment you touch it in any way.

>  > (Another theoretical difference is that a deferred expression is
>  > parsed in the context of its *usage* rather than its *definition*, but
>  > that would break all manner of things in Python and is quite
>  > impractical.)
>
> I'm a little confused by "theoretical" and "parsed".  I guess by
> "theoretical" you mean that this is a design choice, and by "parsed in
> the context" you mean that the expression could be represented in the
> deferred object as a string, an AST, or a code object.  Please
> confirm.
>

What I mean is that I don't know whether you intend it one way or the
other, so I don't know whether it's an actual difference in your
proposal, or something that could in theory be.

If name lookups in these temporary expressions have to refer to names
in the target function, not in their current context, it causes all
kinds of problems. Is that your intention? Otherwise, what is x there?

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/ZBFMAOLMZKDYEH5ZIYZID4NZMVTCFCRB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Stephen J. Turnbull
Chris Angelico writes:
 > On Sat, Dec 11, 2021 at 5:35 PM Stephen J. Turnbull
 >  wrote:

 > > foo(x=>[a])

 > I'm not sure what that last line would mean.

This isn't about your proposal, it's about more general syntax.  Not
everything being discussed is about your proposal, and I suspect one
reason you have trouble figuring out what other people are talking
about is that you persistently try to force everything into that
context.

 > My proposal doesn't change the call site in any way, so I'm trying
 > to figure out what you mean by that call. Are you saying that
 > x=>[a] would be an assignment statement that sets x to an
 > unevaluated expression?

No, I'm saying it would be an assignment expression (like :=), but
that's what it would do.  But that binding would be ignored, and the
value passed into the function in the usual way.  A keyword argument
would be set with the even uglier x = (x=>[a]).

 > If so, that's independent of the default argument.

Of course it is, because it's a device to pass a general "deferred
object" which is constructed in the actual argument list.

 > If it's a special way to pass keyword arguments to a
 > function,

No.  In fact in this context x is a dummy, as ugly as any crash test
dummy after the crash.  I probably should have used _.

 > It would also require significant changes to the way that nonlocal
 > names are looked up (or would be restricted in what nonlocals it
 > can refer to, possibly none at all).

All of which should clue you in that that's probably not what I'm
talking about, especially when I explicitly wrote "while in an
executable context, it could return the object, as := does".

 > Indeed. But here's the question: If a deferred object is to be a
 > replacement for default_factory, then it must by definition be able to
 > be stored for later. So it can't be autoevaluated unless there's some
 > mechanism for delaying the autoevaluation. This seems like an
 > incredibly messy approach.

Such an object is not evaluated when created; it's evaluated when
referenced, like a descriptor.  Descriptors are messy, too, but
very useful.

 > The use-cases for deferred evaluation differ

Yup.  It's an object, those use-cases can "almost certainly" (IMHO,
but I suspect David and Eric agree) be distinguished by attributes set
on the object, or auxiliary APIs for special use-cases where you want
the unevaluated object.  I suspect that most folks who want "deferred
objects" haven't really thought about this issue, but have focused on
their immediate applications.

 > What would have overlap with argument defaults isn't the same thing
 > that would be useful for dataclasses.

If you say so, but forgive me if I table your comment and wait for
Eric to weigh in on requirements related to dataclasses.  In any case,
if the default is such a deferred object x, I'm pretty sure that doing
x=x before entering the function body is equivalent to your proposal.
I see no particular reason why we couldn't have that rule for
"deferred objects" created in "function signature scope".

Steve
___
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/LCMG3JZLBNY45CWH6YNVLAW2EYIOXBFD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: PEP 671 (late-bound arg defaults), next round of discussion!

2021-12-11 Thread Stephen J. Turnbull
Chris Angelico writes:

 > It's larger than argument defaults, but also smaller:

Aside: I'm quite confused by your whole line of discussion here, but
I'll let Eric follow up.

 > The overlap with late-bound defaults is the simple case of mutable
 > objects that you want to freshly construct every time, but
 > ultimately, that's not hugely different from a lambda function:

Of course it's hugely different from a lambda function.  It will be
evaluated at the time of reference, whereas a lambda function will
not, it won't be evaluated until called.  (This means that to access a
deferred object without evaluating it, a separate API will be needed,
sort of the dual of function call.)

 > (Another theoretical difference is that a deferred expression is
 > parsed in the context of its *usage* rather than its *definition*, but
 > that would break all manner of things in Python and is quite
 > impractical.)

I'm a little confused by "theoretical" and "parsed".  I guess by
"theoretical" you mean that this is a design choice, and by "parsed in
the context" you mean that the expression could be represented in the
deferred object as a string, an AST, or a code object.  Please
confirm.

___
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/5NFYE4Z5PU7QCBDBV2IUMYLCPMGGY7TX/
Code of Conduct: http://python.org/psf/codeofconduct/