[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Eric V. Smith

On 5/20/2021 3:24 PM, Ronald Oussoren via Python-Dev wrote:



On 20 May 2021, at 19:10, Luciano Ramalho > wrote:


I'd like to learn about use cases where `...` (a.k.a. `Ellipsis`) is
not a good sentinel. It's a pickable singleton testable with `is`,
readily available, and extremely unlikely to appear in a data stream.
Its repr is "Ellipsis".

If you don't like the name for this purpose, you can always define a
constant (that won't fix the `repr`, obviously, but helps with source
code readability).

SENTINEL = ...

I can't think of any case where I'd rather have my own custom
sentinel, or need a special API for sentinels. Probably my fault, of
course. Please enlighten me!


One use case for a sentinel that is not a predefined (builtin) 
singleton is APIs where an arbitrary user specified value can be used.


One example of this is the definition of dataclasses.field:

|dataclasses.||field|(/*/, /default=MISSING/, 
/default_factory=MISSING/, /repr=True/, /hash=None/, /init=True/, 
/compare=True/, /metadata=None/)


Here the “default” and “default_factory” can be an arbitrary value, 
and any builtin singleton could be used. Hence the use of a custom 
module-private sentinel that cannot clash with values used by users of 
the module (unless those users poke at private details of the module, 
but then all bets are off anyway).


That’s why I don’t particularly like the proposal of using Ellipsis as 
the sanctioned sentinel value. It would be weird at best that the 
default for a dataclass field can be any value, except for the builtin 
Ellipsis value.


Completely agree. I'm opposed to Ellipsis as a sentinel for this reason, 
at least for dataclasses. I can easily see wanting to store an Ellipsis 
in a field of a dataclass that's describing a function's parameters. And 
I can even see it being the default= value. Not so much 
default_factory=, but they may as well be the same.


Eric

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/E3R6LVOBOX5HOWGFDE7TVDCDHI4QAK2Y/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Critique of PEP 657 -- Include Fine Grained Error Locations in Tracebacks

2021-05-20 Thread Pablo Galindo Salgado
> Hopefully if we add more pseudokeywords in the future it won't break
the ability to parse traceback spans.

It won't because soft keywords are now handled natively with the peg
parser (as "match" and "case" now) instead of hacked into the tokenizer :)


On Fri, 21 May 2021 at 01:55, Nathaniel Smith  wrote:

> On Wed, May 19, 2021 at 7:28 PM Pablo Galindo Salgado
>  wrote:
> >>
> >> Excellent point! Do you know how reliable this is in practice, i.e.
> >> what proportion of bytecode source spans are something you can
> >> successfully pass to ast.parse? If it works it's obviously nicer, but
> >> I can't tell how often it works. E.g. anything including
> >> return/break/continue/yield/await will fail, since those require an
> >> enclosing context to be legal. I doubt return/break/continue will
> >> raise exceptions often, but yield/await do all the time.
> >
> >
> > All those limitations are compiler-time limitations because they imply
> > scoping. A valid AST is any piece of a converted parse tree, or a piece
> > of the PEG sub grammar:
> >
> > >>> ast.dump(ast.parse("yield"))
> > 'Module(body=[Expr(value=Yield())], type_ignores=[])'
> > >>> ast.dump(ast.parse("return"))
> > 'Module(body=[Return()], type_ignores=[])'
> > >>> ast.dump(ast.parse("continue"))
> > 'Module(body=[Continue()], type_ignores=[])'
> > >>> ast.dump(ast.parse("await x"))
> > "Module(body=[Expr(value=Await(value=Name(id='x', ctx=Load(],
> type_ignores=[])"
>
> Ah, nice! I guess I was confused by memories of the behavior in 3.6
> and earlier, where 'await' was a pseudokeyword:
>
> ❯ docker run -it --rm python:3.6-alpine
> >>> import ast
> >>> ast.parse("await f()")
> SyntaxError: invalid syntax
>
> Hopefully if we add more pseudokeywords in the future it won't break
> the ability to parse traceback spans.
>
> -n
>
> --
> Nathaniel J. Smith -- https://vorpus.org
>
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/RQ65HRD47SR73B256EUXPUCSVY65USDV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Critique of PEP 657 -- Include Fine Grained Error Locations in Tracebacks

2021-05-20 Thread Nathaniel Smith
On Wed, May 19, 2021 at 7:28 PM Pablo Galindo Salgado
 wrote:
>>
>> Excellent point! Do you know how reliable this is in practice, i.e.
>> what proportion of bytecode source spans are something you can
>> successfully pass to ast.parse? If it works it's obviously nicer, but
>> I can't tell how often it works. E.g. anything including
>> return/break/continue/yield/await will fail, since those require an
>> enclosing context to be legal. I doubt return/break/continue will
>> raise exceptions often, but yield/await do all the time.
>
>
> All those limitations are compiler-time limitations because they imply
> scoping. A valid AST is any piece of a converted parse tree, or a piece
> of the PEG sub grammar:
>
> >>> ast.dump(ast.parse("yield"))
> 'Module(body=[Expr(value=Yield())], type_ignores=[])'
> >>> ast.dump(ast.parse("return"))
> 'Module(body=[Return()], type_ignores=[])'
> >>> ast.dump(ast.parse("continue"))
> 'Module(body=[Continue()], type_ignores=[])'
> >>> ast.dump(ast.parse("await x"))
> "Module(body=[Expr(value=Await(value=Name(id='x', ctx=Load(], 
> type_ignores=[])"

Ah, nice! I guess I was confused by memories of the behavior in 3.6
and earlier, where 'await' was a pseudokeyword:

❯ docker run -it --rm python:3.6-alpine
>>> import ast
>>> ast.parse("await f()")
SyntaxError: invalid syntax

Hopefully if we add more pseudokeywords in the future it won't break
the ability to parse traceback spans.

-n

-- 
Nathaniel J. Smith -- https://vorpus.org
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/OGGRDHOPOVXS25UMYYLZ55FGDMA25UMU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 659: Specializing Adaptive Interpreter

2021-05-20 Thread Christopher Barker
I find this whole conversation confusing -- does anyone really think a
substantial performance boost to cPython is not a "good thing"? Worth the
work? Maybe not, but it seems that Mark, Guido, and MS think it is -- more
power to them!

Anyway:

potential 10% or 20% speedups in Python


I believe the folks involved think they may get a factor of two speedup --
but in any case, Oscar has a point -- there is a trade-off of effort vs
performance, and increasing the performance of cPython moves that trade-off
point, even if just a little.

I like Oscar's example, because it's got hard numbers attached to it, but
the principle is the same for any time you are considering writing, or even
using, a non-python library.


>  (2) bite the bullet and write
> C (or ctypes) that can do the calculations 100x as fast as a
> well-tuned Python program.
>

Oddly missing from this conversation is PyPy -- which can buy you a lot of
performance for some types of code in pure Python, and things like Cython
or numba, which can buy you a lot with slightly modified Python.

All those options are why Python is very useful today -- but none of them
make the case that making cPython run faster isn't a worthy goal.

-CHB

-- 
Christopher Barker, PhD (Chris)

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/3WIXL4PIWDXZPVVMQJWWXV3GNO3ED3ZC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 659: Specializing Adaptive Interpreter

2021-05-20 Thread Stephen J. Turnbull
Oscar Benjamin writes:

 > The break even point where both implementations take equal time is
 > around about 5% density. What that means is that for a 1000 x 1000
 > matrix with 10% of elements nonzero it is faster to ask flint to
 > construct an enormous dense matrix and perform a huge number of
 > arithmetic operations (mostly involving zeros) than it is to use a
 > pure Python implementation that has more favourable asymptotic
 > complexity and theoretically computes the result with 100x fewer
 > arithmetic "operations". In this situation there is a sliding scale
 > where the faster the Python interpreter gets the less often you
 > benefit from calling the C routine in the first place.

Sure, but what's also happening here is that you're optimizing
programmer cost by not writing the sparse algorithm in C, C++, or
Rust.  So I haven't done the math, but I guess to double the
percentage of nonzero matrix elements that constitutes the breakeven
point you need to double the speed of the Python runtime, and I don't
think that's going to happen any time soon.  As far as I can see, any
reasonably anticipatable speedup is quite marginal for you (a 10%
speedup in arithmetic is, I hope, a dream, but that would get you from
5% to 5.5% -- is that really a big deal?)

 > This happens because it works out faster from the perspective of
 > pure Python code that is encumbered by interpreter overhead and has
 > a limited range of C routines to choose from. If the interpreter
 > overhead is less then the options to choose from are improved.

Absolutely.  But the real problem you face is that nobody is writing
routines for sparse matrices in languages that compile to machine code
(or worse, not wrapping already available C libraries).  

 > In the case of SymPy/flint if the maximum speed gain of flint was only
 > 10x then I might not bother using it at all to avoid the complexity of
 > having multiple implementations to choose from and external
 > dependencies etc.

Sure, but my guesstimate is that that would require a 90% speedup in
Python arithmetic.  Really, is that going to happen?

I feel your pain (even though for me it's quite theoretical, my own
data is dense, even impenetrable).  But I just don't see even
potential 10% or 20% speedups in Python overcoming the generic need
for programmers to either (1) accept the practical limits to the size
of data they can work with in Python or (2) bite the bullet and write
C (or ctypes) that can do the calculations 100x as fast as a
well-tuned Python program.

I'm all for Mark's work, and I'm glad somebody's willing to pay him
some approximation to what he's worth, even though I probably won't
benefit myself (nor my students).  But I really don't see the
economics of individual programmers changing very much -- 90% of us
will just use the tried-and-true packages (some of which are
accelerated like NumPy and Pandas), 9% will think for ten minutes and
choose (1) or (2) above, and 1% will do the careful breakeven analysis
you do, and write (and deal with the annoyances of) hybrid code.

Steve
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/UWLGL6HGTM6LIUOS2HFZX23GFJDXQPG7/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread micro codery
>  > But it nevertheless feels like a bit of an abuse - the original point
>>  > of ellipsis was for indexing, and in particular complex slices like
>>  > a[1:20:2, ..., 3:5]. That usage is common in numpy, as I understand
>>  > it,
>> Interesting -- do you know what ... means in that context?
>>
>
> In NumPy, the ellipsis means "fill in as many dimensions as needed (with
> full range)".
>

I am in the same boat here in that until now I saw Ellipsis as a thing used
by numpy and adjacent libraries in slicing. I don't think I have ever
written a slice with "..." in it so please forgive any ignorance but wasn't
the reason for having Ellipsis originally that None already had a special
meaning to the slice object and a different sentinel was needed? In other
words the normal case of a missing argument being None caused specific side
effects that needed to be skipped, so a sentinel was created to distinguish
these cases, just like we are discussing for other objects? It seems to me
the current situation has more in common than not. Numpy could have created
its own Sentinel object for its own use in these sliceses, just as it now
creates its own Sentinel for NoValue, but somewhere along the way it was
determined to be in the better interest of the community to have this
object defined in the standard library so it could be shared by multiple
scientific libraries without additional dependency burden, even though it
had no use to CPython.

I think there was perhaps a time when Ellipsis was so closely tied to the
scientific libraries that recommending its use anywhere else would have
been a poor idea, probably mostly because of the body of existing teaching
around its use; but I also think that association is no longer as strong.
"..." is being adopted across the typing landscape with several PEPs, such
as 483, outlining their special meaning in annotations. In addition, stub
files have since the beginning normalized on putting "..." as the
function body despite already having the working conventions of `pass`
`NotImplemented` or just a good old empty docstring "" filling the same
purpose in standard python files.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/IEF42DESJEJITI4HR5SJZHM3FDILKX6Q/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Tal Einat
On Thu, May 20, 2021 at 10:37 PM David Mertz  wrote:
>
> The scenario I'm thinking about is like this:
>
> (base) 84-tmp % python
> Python 3.9.1 (default, Dec 11 2020, 14:32:07)
> [GCC 7.3.0] :: Anaconda, Inc. on linux
> Type "help", "copyright", "credits" or "license" for more information.
> >>> import pickle
> >>> cheap_sentinel = object()
> >>> id(cheap_sentinel)
> 140469343429632
> >>> pickle.dump(cheap_sentinel, open('sentinel.pkl', 'wb'))
>
> (base) 85-tmp % python
> Python 3.9.1 (default, Dec 11 2020, 14:32:07)
> [GCC 7.3.0] :: Anaconda, Inc. on linux
> Type "help", "copyright", "credits" or "license" for more information.
> >>> import pickle
> >>> cheap_sentinel = object()
> >>> id(cheap_sentinel)
> 139852505814016
> >>> id(pickle.load(open('sentinel.pkl', 'rb')))
> 139852505813968
>
> It would be pleasant if there were a way to make "cheap_sentinel" be the same 
> thing—either by equality or by identity—betweeen those two runs of the 
> interpreter.
>
> None or Ellipsis have that property, of course.  So do, for example, 
> integers, at least by equality if not identity (yes, of course, we might get 
> identity by interning, but it's not guaranteed).

There are several ways of achieving this for other sentinel values,
some of which have been mentioned earlier in this thread. Some
examples are:

1. a value from a single-valued enum
2. a class object (not an instance)
3. a singleton class with a carefully implemented __new__ which always
returns the same instance

- Tal Einat
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/RJXU7F6LYVJ4C4N4EPVA3A5F3QRGK253/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 659: Specializing Adaptive Interpreter

2021-05-20 Thread Terry Reedy

On 5/20/2021 10:49 AM, Oscar Benjamin wrote:

On Thu, 20 May 2021 at 04:58, Terry Reedy  wrote:



I believe the ratio for the sort of numerical computing getting bogus
complaints is sometimes more like 95% of *time* in compiled C and only,
say, 5% of *time* in the Python interpreter.  So even if the interpreter
ran instantly, it would make also no difference -- for such applications.


'also' was meant to be 'almost'


Not necessarily


In the context I carefully defined, where Python is falsely accused of 
endangering the earth, by people who set up strawpeople images of how 
Python is actually used and who care nothing about programmer time and 
joy, yes, necessarily.  However, in the related context you define, 
faster Python could help save the earth by reducing the need for 
brute-force C routines when they are grossly inefficient.  How ironic 
that would be.



because if the interpreter is faster then it opens up
new options that perhaps don't involve the same C routines. The
situation right now is that it is often faster to do more
"computation" than needed using efficient C routines rather than do
precisely what is needed in bare Python. If the bare Python part
becomes faster then maybe you don't need the C routine at all.

To give a concrete example, in SymPy I have written a pure Python
implementation of typed sparse matrices (this is much faster than the
public Matrix class so don't compare with that). I would like to use
the flint library to speed up some of these matrix calculations and
the flint library has a highly optimised C/assembly implementation of
dense matrices of arbitrary precision integers. Which of these
implementations is faster for e.g. matrix multiplication depends on
how sparse the matrix actually is. If I have a large matrix say 1000 x
1000 and only 1% of the elements are nonzero then the pure Python
sparse implementation is faster (it can be much faster as the density
reduces since it does not have the same big-O characteristics). On the
other hand for fully dense matrices where all elements are nonzero the
flint implementation is consistently around 100x faster.

The break even point where both implementations take equal time is
around about 5% density. What that means is that for a 1000 x 1000
matrix with 10% of elements nonzero it is faster to ask flint to
construct an enormous dense matrix and perform a huge number of
arithmetic operations (mostly involving zeros) than it is to use a
pure Python implementation that has more favourable asymptotic
complexity and theoretically computes the result with 100x fewer
arithmetic "operations". In this situation there is a sliding scale
where the faster the Python interpreter gets the less often you
benefit from calling the C routine in the first place.

Although this is a very specific example it illustrates something that
I see very often which is that while the efficient C routines can make
things "run at the speed of C" you can often end up optimising things
to use an approach that would seem inefficient if you were working in
C directly. This happens because it works out faster from the
perspective of pure Python code that is encumbered by interpreter
overhead and has a limited range of C routines to choose from. If the
interpreter overhead is less then the options to choose from are
improved.

Also for many applications it is much easier for the programmer to
write an algorithm directly in loops rather than coming up with a
vectorised version based on e.g. numpy arrays. Vectorisation as a way
of optimising code is actually work for the programmer. There is
another tradeoff here which is not about C speed vs Python speed but
about programmer time vs CPU time. If a straight-forward Python
implementation is already "fast enough" then you don't need to spend
time thinking about how to translate that into something that would
possibly run faster (potentially at the expense of code readability).
In the case of SymPy/flint if the maximum speed gain of flint was only
10x then I might not bother using it at all to avoid the complexity of
having multiple implementations to choose from and external
dependencies etc.

--
Oscar




--
Terry Jan Reedy

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/PLPOOWB6KRBSIBZLM5NOP2O5AJGAN2AB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread David Mertz
The scenario I'm thinking about is like this:

(base) 84-tmp % python
Python 3.9.1 (default, Dec 11 2020, 14:32:07)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> cheap_sentinel = object()
>>> id(cheap_sentinel)
140469343429632
>>> pickle.dump(cheap_sentinel, open('sentinel.pkl', 'wb'))

(base) 85-tmp % python
Python 3.9.1 (default, Dec 11 2020, 14:32:07)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> cheap_sentinel = object()
>>> id(cheap_sentinel)
139852505814016
>>> id(pickle.load(open('sentinel.pkl', 'rb')))
139852505813968

It would be pleasant if there were a way to make "cheap_sentinel" be the
same thing—either by equality or by identity—betweeen those two runs of the
interpreter.

None or Ellipsis have that property, of course.  So do, for example,
integers, at least by equality if not identity (yes, of course, we might
get identity by interning, but it's not guaranteed).

On Thu, May 20, 2021 at 3:10 PM Ethan Furman  wrote:

> On 5/20/21 10:47 AM, David Mertz wrote:
>  > On Thu, May 20, 2021 at 6:21 AM Tal Einat wrote:
>
>  >> I think it's worth preserving the idiom of comparing sentinels using
>  >> `is`, as we do for `None` and other existing sentinel values. It's
>  >> relatively easy to do, such as by using a single-value Enum or by
>  >> using a class with a custom __new__.
>  >
>  >
>  > This only works if:
>  >
>  > a) Unpickling is within a single interpreter session
>
> I don't understand.  If I pickle a sentinel in session A, then unpickle it
> in session B, why wouldn't I get the "same"
> sentinel?
>
>  > b) Sentinels are explicitly created in imported modules, not as a
> runtime, user-level creation
>
> Why would you ever have a sentinel not always created?
>
> Hoping-to-learn-something-new'ly yrs,
>
> --
> ~Ethan~
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/OLTV44EVHJL3C4AIFPGUINZAZNI3YNNK/
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
The dead increasingly dominate and strangle both the living and the
not-yet born.  Vampiric capital and undead corporate persons abuse
the lives and control the thoughts of homo faber. Ideas, once born,
become abortifacients against new conceptions.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/S2PXT2FPB436CZW7C75FN5JQRVZR7LMZ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Sebastian Berg
On Thu, 2021-05-20 at 19:00 +0100, Paul Moore wrote:
> On Thu, 20 May 2021 at 18:13, Luciano Ramalho 
> wrote:
> > 
> > I'd like to learn about use cases where `...` (a.k.a. `Ellipsis`)
> > is
> > not a good sentinel. It's a pickable singleton testable with `is`,
> > readily available, and extremely unlikely to appear in a data
> > stream.
> > Its repr is "Ellipsis".
> 
> Personally, I'm quite tempted by the idea of using ellipsis. It just
> sort of feels reasonable (and in the context `def f(x,
> optional_arg=...)` it even looks pretty natural).
> 
> But it nevertheless feels like a bit of an abuse - the original point
> of ellipsis was for indexing, and in particular complex slices like
> a[1:20:2, ..., 3:5]. That usage is common in numpy, as I understand
> it, even if it's relatively rare in everyday Python. So while I like
> the idea in principle, I'm mildly worried that it's not "the right
> thing to do".
> 
> I can't put my ambivalence about the idea any more precisely than
> this, unfortunately.


In NumPy we use a "missing argument" sentinel currently.  Mainly for
things roughly like:


def mean(arr, *, axis=np._NoValue):
if not hasattr(arr, "mean"):
# Not a duck that defines `mean`, coerce to ndarray:
arr = np.asarray(arr)

if axis is np._NoValue:
return arr.mean()
return arr.mean(axis=axis)


This allows us to add new keyword arguments without breaking backward
compatibility.  I do not remember if we had particularly important
reasons for not wanting to drop the default `None`, or it was just
erring on the safe side.


In any case, I tend to agree that `Ellipsis` should be considered
"user-facing" value.  And in the above code, we do not expect anyone to
ever call `np.mean(something, axis=np._NoValue)` – its not even
accessible – but if the value was `...` then I would expect users to be
encouraged to write `np.mean(arr, axis=...)` in normal code.

More importantly, I can think of a reasonable "meaning" for `axis=...`!
In NumPy `axis=None` (default) returns a scalar, `axis=...` could
return a 0-D array.
This would borrow meanings that `Ellipsis` carries in indexing. [1]

Cheers,

Sebastian



[1] In such a mental model, it would mean the same as
`axis=range(arr.ndim)`.  To be clear, NumPy doesn't do this, its just a
plausible meaning if it has to continue to juggle scalars and 0-D
arrays and wants to be "clearer" about it.



> 
> Paul
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at 
> https://mail.python.org/archives/list/python-dev@python.org/message/ZGMZRGHFXQQZZLKBBZKXXAO65TRB6VYX/
> Code of Conduct: http://python.org/psf/codeofconduct/
> 


___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/M2X6VMEDFNZ4GA3CLXKXMA56SNCEPX4O/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Ronald Oussoren via Python-Dev


> On 20 May 2021, at 19:10, Luciano Ramalho  wrote:
> 
> I'd like to learn about use cases where `...` (a.k.a. `Ellipsis`) is
> not a good sentinel. It's a pickable singleton testable with `is`,
> readily available, and extremely unlikely to appear in a data stream.
> Its repr is "Ellipsis".
> 
> If you don't like the name for this purpose, you can always define a
> constant (that won't fix the `repr`, obviously, but helps with source
> code readability).
> 
> SENTINEL = ...
> 
> I can't think of any case where I'd rather have my own custom
> sentinel, or need a special API for sentinels. Probably my fault, of
> course. Please enlighten me!

One use case for a sentinel that is not a predefined (builtin) singleton is 
APIs where an arbitrary user specified value can be used.

One example of this is the definition of dataclasses.field:

dataclasses.field(*, default=MISSING, default_factory=MISSING, 
repr=True, hash=None, init=True, compare=True, metadata=None)

Here the “default” and “default_factory” can be an arbitrary value, and any 
builtin singleton could be used. Hence the use of a custom module-private 
sentinel that cannot clash with values used by users of the module (unless 
those users poke at private details of the module, but then all bets are off 
anyway).

That’s why I don’t particularly like the proposal of using Ellipsis as the 
sanctioned sentinel value. It would be weird at best that the default for a 
dataclass field can be any value, except for the builtin Ellipsis value.

Ronald

> 
> Cheers,
> 
> Luciano
> 
> On Thu, May 20, 2021 at 8:35 AM Victor Stinner  wrote:
>> 
>> IMO you should consider writing a PEP to enhance sentinels in Python,
>> and maybe even provide a public API for sentinels in general.
>> 
>> Victor
>> ___
>> Python-Dev mailing list -- python-dev@python.org
>> To unsubscribe send an email to python-dev-le...@python.org
>> https://mail.python.org/mailman3/lists/python-dev.python.org/
>> Message archived at 
>> https://mail.python.org/archives/list/python-dev@python.org/message/EY6B6PRQ2B54FVG5JK42GR6ZM2VQ7VL2/
>> Code of Conduct: http://python.org/psf/codeofconduct/
> 
> 
> 
> -- 
> Luciano Ramalho
> |  Author of Fluent Python (O'Reilly, 2015)
> | http://shop.oreilly.com/product/0636920032519.do
> |  Technical Principal at ThoughtWorks
> |  Twitter: @ramalhoorg
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at 
> https://mail.python.org/archives/list/python-dev@python.org/message/WNCFFIJHLS5NCA5QZG5JA45U2DKEETGI/
> Code of Conduct: http://python.org/psf/codeofconduct/

—

Twitter / micro.blog: @ronaldoussoren
Blog: https://blog.ronaldoussoren.net/

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/U5KUT6F6SETJZFCPJISNAZNYJZMJD5BP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Paul Moore
On Thu, 20 May 2021 at 20:06, Ethan Furman  wrote:
>
> On 5/20/21 11:00 AM, Paul Moore wrote:
>
>  > But it nevertheless feels like a bit of an abuse - the original point
>  > of ellipsis was for indexing, and in particular complex slices like
>  > a[1:20:2, ..., 3:5]. That usage is common in numpy, as I understand
>  > it,
>
> Interesting -- do you know what ... means in that context?

In general, it just means a.getitem((slice(1,20,2), Ellipsis,
slice(3,5))), which has no specifically-defined meaning. In numpy, it
means something along the lines of "broadcast along this axis" (I
don't know the numpy terminology very well).

Paul
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/FFKSIHKW2CAQUMBWA6YUDKTGDKNSEQBB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread David Mertz
On Thu, May 20, 2021 at 3:03 PM Ethan Furman  wrote:

>  > But it nevertheless feels like a bit of an abuse - the original point
>  > of ellipsis was for indexing, and in particular complex slices like
>  > a[1:20:2, ..., 3:5]. That usage is common in numpy, as I understand
>  > it,
> Interesting -- do you know what ... means in that context?
>

In NumPy, the ellipsis means "fill in as many dimensions as needed (with
full range)".

So e.g., if I have a 5-D array, and I want just a portion from the first
and last dimension (but everything from the middle ones), I can type:

a[1:20:2, :, :, :, 3:5]

But as a simplification, I can use the example given:

a[1:20:2, ..., 3:5]

This is particularly useful since in NumPy it is not uncommon to expand or
contract the number of dimensions (often with some dimensions having only a
span of 1).  If you don't want to think about which version of the
high-dimensional array you are working with (that might have been
.flatten()'d, .squeeze()'d, or .expand_dims()'d), this is sometimes more
expressive.


-- 
The dead increasingly dominate and strangle both the living and the
not-yet born.  Vampiric capital and undead corporate persons abuse
the lives and control the thoughts of homo faber. Ideas, once born,
become abortifacients against new conceptions.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/LDBSVKXWVHWV7CHAY74OQQ5GN24A2MLK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Ethan Furman

On 5/20/21 10:47 AM, David Mertz wrote:
> On Thu, May 20, 2021 at 6:21 AM Tal Einat wrote:

>> I think it's worth preserving the idiom of comparing sentinels using
>> `is`, as we do for `None` and other existing sentinel values. It's
>> relatively easy to do, such as by using a single-value Enum or by
>> using a class with a custom __new__.
>
>
> This only works if:
>
> a) Unpickling is within a single interpreter session

I don't understand.  If I pickle a sentinel in session A, then unpickle it in session B, why wouldn't I get the "same" 
sentinel?


> b) Sentinels are explicitly created in imported modules, not as a runtime, 
user-level creation

Why would you ever have a sentinel not always created?

Hoping-to-learn-something-new'ly yrs,

--
~Ethan~
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/OLTV44EVHJL3C4AIFPGUINZAZNI3YNNK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Ethan Furman

On 5/20/21 11:00 AM, Paul Moore wrote:

> But it nevertheless feels like a bit of an abuse - the original point
> of ellipsis was for indexing, and in particular complex slices like
> a[1:20:2, ..., 3:5]. That usage is common in numpy, as I understand
> it,

Interesting -- do you know what ... means in that context?

--
~Ethan~
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/EKKZP27QJZJD7UA7BXV6TB5EG7NOI2H3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread David Mertz
On Thu, May 20, 2021, 2:11 PM Chris Angelico

> Probably the easiest way would be to have some kind of unique
> identifier (a fully-qualified name) that can be pickled, and then any
> time you attempt to construct a Sentinel with that identifier, it's
> guaranteed to return the same object.


Gosh, almost like a UUID :-).

Actually, there's no reason my ._uuid attribute couldn't simply be the
object id(). That's probably an improvement.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/N6FXEZGYVF562VPIRUAEBPE4JZH76EE4/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Chris Angelico
On Fri, May 21, 2021 at 3:51 AM David Mertz  wrote:
>
> On Thu, May 20, 2021 at 6:21 AM Tal Einat  wrote:
>>
>> On Sat, May 15, 2021 at 2:09 AM David Mertz  wrote:
>> > Just add a ._uuid attribute and have object equality follow equality of 
>> > that attribute. There's no reason to expose that in the .__repr__, but it 
>> > would be inspectable in concept.
>>
>> I think it's worth preserving the idiom of comparing sentinels using
>> `is`, as we do for `None` and other existing sentinel values. It's
>> relatively easy to do, such as by using a single-value Enum or by
>> using a class with a custom __new__.
>
>
> This only works if:
>
> a) Unpickling is within a single interpreter session
> b) Sentinels are explicitly created in imported modules, not as a runtime, 
> user-level creation
>
> Maybe there's a way to do it, but how would you handle this situation:
>
> if some_runtime_condition:
> my_sentinal = Sentinel(desc="Gosh, I need a sentinel")
> # ... code ...
> pickle.dump(thing_using_sentinel, fh)
>
> Equality is certainly a lot easier to get than identity here.
>

Probably the easiest way would be to have some kind of unique
identifier (a fully-qualified name) that can be pickled, and then any
time you attempt to construct a Sentinel with that identifier, it's
guaranteed to return the same object. That way, in your example,
unpickling it in another session where that runtime condition is false
would simply create a brand new sentinel, which would be the same as
any others that also get unpickled; and if, subsequently, you
reconstruct my_sentinal, it would be the same one as got unpickled.

The hardest part would be figuring out a reliable way to define the
identifier, without massively duplicating or requiring that something
be registered somewhere.

ChrisA
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/3WKMD7Q3JMLDWI3L2WOGIJB767PYJO2W/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Paul Moore
On Thu, 20 May 2021 at 18:13, Luciano Ramalho  wrote:
>
> I'd like to learn about use cases where `...` (a.k.a. `Ellipsis`) is
> not a good sentinel. It's a pickable singleton testable with `is`,
> readily available, and extremely unlikely to appear in a data stream.
> Its repr is "Ellipsis".

Personally, I'm quite tempted by the idea of using ellipsis. It just
sort of feels reasonable (and in the context `def f(x,
optional_arg=...)` it even looks pretty natural).

But it nevertheless feels like a bit of an abuse - the original point
of ellipsis was for indexing, and in particular complex slices like
a[1:20:2, ..., 3:5]. That usage is common in numpy, as I understand
it, even if it's relatively rare in everyday Python. So while I like
the idea in principle, I'm mildly worried that it's not "the right
thing to do".

I can't put my ambivalence about the idea any more precisely than
this, unfortunately.

Paul
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/ZGMZRGHFXQQZZLKBBZKXXAO65TRB6VYX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread David Mertz
On Thu, May 20, 2021 at 6:21 AM Tal Einat  wrote:

> On Sat, May 15, 2021 at 2:09 AM David Mertz  wrote:
> > Just add a ._uuid attribute and have object equality follow equality of
> that attribute. There's no reason to expose that in the .__repr__, but it
> would be inspectable in concept.
>
> I think it's worth preserving the idiom of comparing sentinels using
> `is`, as we do for `None` and other existing sentinel values. It's
> relatively easy to do, such as by using a single-value Enum or by
> using a class with a custom __new__.
>

This only works if:

a) Unpickling is within a single interpreter session
b) Sentinels are explicitly created in imported modules, not as a runtime,
user-level creation

Maybe there's a way to do it, but how would you handle this situation:

if some_runtime_condition:
my_sentinal = Sentinel(desc="Gosh, I need a sentinel")
# ... code ...
pickle.dump(thing_using_sentinel, fh)

Equality is certainly a lot easier to get than identity here.

-- 
The dead increasingly dominate and strangle both the living and the
not-yet born.  Vampiric capital and undead corporate persons abuse
the lives and control the thoughts of homo faber. Ideas, once born,
become abortifacients against new conceptions.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/KJ57424FRXV3G4M2AXV5DLD5JZKAP43Z/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Luciano Ramalho
I'd like to learn about use cases where `...` (a.k.a. `Ellipsis`) is
not a good sentinel. It's a pickable singleton testable with `is`,
readily available, and extremely unlikely to appear in a data stream.
Its repr is "Ellipsis".

If you don't like the name for this purpose, you can always define a
constant (that won't fix the `repr`, obviously, but helps with source
code readability).

SENTINEL = ...

I can't think of any case where I'd rather have my own custom
sentinel, or need a special API for sentinels. Probably my fault, of
course. Please enlighten me!

Cheers,

Luciano

On Thu, May 20, 2021 at 8:35 AM Victor Stinner  wrote:
>
> IMO you should consider writing a PEP to enhance sentinels in Python,
> and maybe even provide a public API for sentinels in general.
>
> Victor
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at 
> https://mail.python.org/archives/list/python-dev@python.org/message/EY6B6PRQ2B54FVG5JK42GR6ZM2VQ7VL2/
> Code of Conduct: http://python.org/psf/codeofconduct/



-- 
Luciano Ramalho
|  Author of Fluent Python (O'Reilly, 2015)
| http://shop.oreilly.com/product/0636920032519.do
|  Technical Principal at ThoughtWorks
|  Twitter: @ramalhoorg
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/WNCFFIJHLS5NCA5QZG5JA45U2DKEETGI/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 659: Specializing Adaptive Interpreter

2021-05-20 Thread Oscar Benjamin
On Thu, 20 May 2021 at 04:58, Terry Reedy  wrote:
>
> On 5/13/2021 4:18 AM, Mark Shannon wrote:
>
> > If a program does 95% of its work in a C++ library and 5% in Python, it
> > can easily spend the majority of its time in Python because CPython is a
> > lot slower than C++ (in general).
>
> I believe the ratio for the sort of numerical computing getting bogus
> complaints is sometimes more like 95% of *time* in compiled C and only,
> say, 5% of *time* in the Python interpreter.  So even if the interpreter
> ran instantly, it would make also no difference -- for such applications.

Not necessarily because if the interpreter is faster then it opens up
new options that perhaps don't involve the same C routines. The
situation right now is that it is often faster to do more
"computation" than needed using efficient C routines rather than do
precisely what is needed in bare Python. If the bare Python part
becomes faster then maybe you don't need the C routine at all.

To give a concrete example, in SymPy I have written a pure Python
implementation of typed sparse matrices (this is much faster than the
public Matrix class so don't compare with that). I would like to use
the flint library to speed up some of these matrix calculations and
the flint library has a highly optimised C/assembly implementation of
dense matrices of arbitrary precision integers. Which of these
implementations is faster for e.g. matrix multiplication depends on
how sparse the matrix actually is. If I have a large matrix say 1000 x
1000 and only 1% of the elements are nonzero then the pure Python
sparse implementation is faster (it can be much faster as the density
reduces since it does not have the same big-O characteristics). On the
other hand for fully dense matrices where all elements are nonzero the
flint implementation is consistently around 100x faster.

The break even point where both implementations take equal time is
around about 5% density. What that means is that for a 1000 x 1000
matrix with 10% of elements nonzero it is faster to ask flint to
construct an enormous dense matrix and perform a huge number of
arithmetic operations (mostly involving zeros) than it is to use a
pure Python implementation that has more favourable asymptotic
complexity and theoretically computes the result with 100x fewer
arithmetic "operations". In this situation there is a sliding scale
where the faster the Python interpreter gets the less often you
benefit from calling the C routine in the first place.

Although this is a very specific example it illustrates something that
I see very often which is that while the efficient C routines can make
things "run at the speed of C" you can often end up optimising things
to use an approach that would seem inefficient if you were working in
C directly. This happens because it works out faster from the
perspective of pure Python code that is encumbered by interpreter
overhead and has a limited range of C routines to choose from. If the
interpreter overhead is less then the options to choose from are
improved.

Also for many applications it is much easier for the programmer to
write an algorithm directly in loops rather than coming up with a
vectorised version based on e.g. numpy arrays. Vectorisation as a way
of optimising code is actually work for the programmer. There is
another tradeoff here which is not about C speed vs Python speed but
about programmer time vs CPU time. If a straight-forward Python
implementation is already "fast enough" then you don't need to spend
time thinking about how to translate that into something that would
possibly run faster (potentially at the expense of code readability).
In the case of SymPy/flint if the maximum speed gain of flint was only
10x then I might not bother using it at all to avoid the complexity of
having multiple implementations to choose from and external
dependencies etc.

--
Oscar
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/BBNEBYO42RAXUM526ZUA65SAQTKCS3QD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Victor Stinner
IMO you should consider writing a PEP to enhance sentinels in Python,
and maybe even provide a public API for sentinels in general.

Victor
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/EY6B6PRQ2B54FVG5JK42GR6ZM2VQ7VL2/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Tal Einat
On Sat, May 15, 2021 at 2:09 AM David Mertz  wrote:
>
> I think it's more future-looking to allow pickle round-tripping.

I tend to agree.

> Just add a ._uuid attribute and have object equality follow equality of that 
> attribute. There's no reason to expose that in the .__repr__, but it would be 
> inspectable in concept.

I think it's worth preserving the idiom of comparing sentinels using
`is`, as we do for `None` and other existing sentinel values. It's
relatively easy to do, such as by using a single-value Enum or by
using a class with a custom __new__.

- Tal
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/XNYLOHY46BWLRXVLPL5RNTLBE6JG5OEX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The repr of a sentinel

2021-05-20 Thread Tal Einat
I've created a poll on this subject:
https://discuss.python.org/t/sentinel-values-in-the-stdlib/8810

On Fri, May 14, 2021 at 10:33 PM Tal Einat  wrote:
>
> On Fri, May 14, 2021 at 12:45 PM Steve Dower  wrote:
> >
> > On 14May2021 0622, micro codery wrote:
> > >
> > > There was a discussion a while back ( a year or so?? ) on
> > > Python-ideas that introduced the idea of having more "sentinel-like"
> > > singletons in Python -- right now, we only have None.
> > >
> > > Not quite true, we also have Ellipsis, which already has a nice repr
> > > that both reads easily and still follows the convention of eval(repr(x))
> > > == x. It also is already safe from instantiation, survives pickle
> > > round-trip and is multi-thread safe.
> > > So long as you are not dealing with scientific projects, it seems a
> > > quick (if dirty) solution to having a sentinel that is not None.
> >
> > I don't think using "..." to indicate "some currently unknown or
> > unspecified value" is dirty at all, it seems perfectly consistent with
> > how we use it in English (and indexing in scientific projects, for that
> > matter, where it tends to imply "figure out the rest for me").
> >
> > All that's really missing is some kind of endorsement (from python-dev,
> > presumably in the docs) that it's okay to use it as a default parameter
> > value. I can't think of any reason you'd need to accept Ellipsis as a
> > *specified* value that wouldn't also apply to any other kind of shared
> > sentinel.
>
> I'll try to organize my thoughts a bit here. This is a bit long,
> welcome to skip to the final sentence for the "tl;dr".
>
> Features one may want for a sentinel:
> 1. Unique from other objects
> 2. Globally unique, i.e. unique from other such sentinels (no consensus here)
> 3. Clear repr (the original subject of this thread) - significant
> since these often appear in function signatures
> 4. Survives pickling round-trip (I brought this up since I was bitten
> by this once, but others have mentioned that this is usually
> irrelevant)
> 5. Can be given a clear type signature (this was brought up on
> twitter[1]) - significant since without this nobody can add full type
> signatures even if they want to
>
> The common `SENTINEL = object()` idiom fails #3, #4 and #5. This is
> what I've been using for years, and I now think that it isn't good
> enough. This not having a nice repr is what started this thread.
>
> I'd also personally prefer something simple, ideally without a new
> class or module.
>
> There are several simple idioms using existing features that seem like
> good options, so let's review those:
>
> 1. Ellipsis, a.k.a. `...`. This has all of the features outlined above
> except #2. My main issue with using Ellipsis for this is that it could
> be surprising and confusing for devs first encountering such use, and
> could be relatively awkward to figure out.
>
> 2. An instance of a one-off class. dataclasses.MISSING is an example
> of this. It is defined thus:
>
> class _MISSING:
> pass
> MISSING = _MISSING()
>
> Besides failing #4 (surviving pickle round-trips), its repr isn't
> great: . That is easily
> overcome by implementing __repr__.
>
> 3. A one-off class:
>
> class MISSING: pass
>
> This has all of the above features except #5: having a clear type
> signature (since its type is type). Using a class as a value this way
> could be surprising, though. It's repr also isn't great:  'dataclasses._MISSING'>.
>
> 4. A value of an single-valued enum, for example (from [1]):
>
> class _UNSET(enum.Enum):
> token = enum.auto()
>
> This has all of the features above and is simple, just requiring a
> comment to explain what it is. It's repr is a bit awkward though:
>
> >>> repr(_UNSET.token)
> '<_UNSET.token: 1>'
>
>
> All of these are in use by some developers, though not necessarily in
> the stdlib. None is perfect, though all are probably good enough.
> Since pickling is likely not relevant in most cases, I'm currently in
> favor of #2 making sure to implement a nice __repr__.
>
> - Tal
>
> [1] https://twitter.com/nolar/status/1392962447166877697
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/77ZBKCJQTG2OFY2WUL33OSJ6H3J57AEP/
Code of Conduct: http://python.org/psf/codeofconduct/