On 14. 05. 21 10:55, Victor Stinner wrote:
Hi Tal,

Would it make sense to have an unique singleton for such sentinel, a
built-in singleton like None or Ellipsis? I propose the name
"Sentinel".

Sentinel would be similar to None, but the main property would be that
"Sentinel is None" is false :-)

If you need your Sentinel to be different from one particular sentinel (None), you'll usually want it to be different from all the other ones as well.

A sentinel for an optional parameter shouldn't really be used at all outside of the function it's defined for. That's why it's usually defined as a private module-level variable.

Perhaps it would be beneficial to provide a common base class or factory, so we get a good repr. But I don't think another common value like None and Ellipsis would do much good.


The stdlib contains tons of sentinels:

* _collections_abc: __marker__
* cgitb.__UNDEF__
* configparser: _UNSET
* dataclasses: _HAS_DEFAULT_FACTORY, MISSING, KW_ONLY
* datetime.timezone._Omitted
* fnmatch.translate() STAR
* functools.lru_cache.sentinel (each @lru_cache creates its own sentinel object)
* functools._NOT_FOUND
* heapq: temporary sentinel in nsmallest() and nlargest()
* inspect._sentinel
* inspect._signature_fromstr() invalid
* plistlib._undefined
* runpy._ModifiedArgv0._sentinel
* sched: _sentinel
* traceback: _sentinel

There are different but similar use cases:

* Optional parameter: distinguish between func() and func(arg=value),
a sentinel is useful to distinguish func() from func(arg=None)
* Look into a data structure for a value and store the result in a
value, distinguish if 'result' variable was set ("result is not None"
doesn't work since None is a value). Quick example: "missing =
object(); tmsg = self._catalog.get(message, missing); if tmsg is
missing: ..."

Special cases:

* dataclases._EMPTY_METADATA = types.MappingProxyType({})
* string._sentinel_dict = {}
* enum: _auto_null = object()

Victor

On Thu, May 13, 2021 at 7:40 PM Tal Einat <talei...@gmail.com> wrote:

On Thu, May 13, 2021 at 7:44 PM Ethan Furman <et...@stoneleaf.us> wrote:

Consider me complaining.  ;-)

+1

An actual Sentinel class would be helpful:

      >>> class Sentinel:
      ...     def __init__(self, repr):
      ...         self.repr = repr
      ...     def __repr__(self):
      ...         return self.repr
      ...

      >>> MISSING = Sentinel('MISSING')
      >>> MISSING
      MISSING

      >>> implicit = Sentinel('<implicit>')
      >>> implicit
      <implicit>

Here is my suggestion (also posted on the related bpo-44123), which is
also simple, ensures a single instance is used, even considering
multi-threading and pickling, and has a better repr:

class Sentinel:
     def __new__(cls, *args, **kwargs):
         raise TypeError(f'{cls.__qualname__} cannot be instantiated')

class MISSING(Sentinel):
     pass

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

Reply via email to