Add new `Symbol` type
More than once I've found myself wanting to create a 'sentinel' value. The most common use case is to differentiate between an argument that has not been provided, and an argument provided with the value `None`. This would be solvable by implementing something similar to what JavaScript calls [`Symbol`]( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Obj... ). This could be implemented as a 3rd-party library, but there won't be a way to have ['Global' Symbols]( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Obj... ) Furthermore, without a common implementation in the std library, various Python libraries had to write their own implementations, which all differs in functionality and behavior. Is this something that the Python community is interested in? I'm willing to write the PEP
Hi! On 2018-07-05 20:38, Flavio Curella wrote:
More than once I've found myself wanting to create a 'sentinel' value. The most common use case is to differentiate between an argument that has not been provided, and an argument provided with the value `None`.
I generally do something like _nothing = object()
Furthermore, without a common implementation in the std library, various Python libraries had to write their own implementations, which all differs in functionality and behavior.
What functionality does such a thing actually need?
I have also wanted sentinel objects many times. These are often useful for creating a "Not Specified" default value when explicitly passing `None` has semantic meaning. There are a few issues with the `sentinel = object()` code. One is that they don't repr well so they make debugging harder. Another issue is that they cannot be pickled or copied. You also cannot take a weak reference to a sentinel which can break some caching code and makes them harder to use. At work we have a small helper to create sentinels with a name and optional doc string which is open sourced here: https://github.com/quantopian/zipline/blob/master/zipline/utils/sentinel.py. On Thu, Jul 5, 2018 at 3:44 PM, Ed Kellett <e+python-ideas@kellett.im> wrote:
Hi!
On 2018-07-05 20:38, Flavio Curella wrote:
More than once I've found myself wanting to create a 'sentinel' value. The most common use case is to differentiate between an argument that has not been provided, and an argument provided with the value `None`.
I generally do something like
_nothing = object()
Furthermore, without a common implementation in the std library, various Python libraries had to write their own implementations, which all differs in functionality and behavior.
What functionality does such a thing actually need? _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Thu, Jul 05, 2018 at 02:38:47PM -0500, Flavio Curella wrote:
More than once I've found myself wanting to create a 'sentinel' value. The most common use case is to differentiate between an argument that has not been provided, and an argument provided with the value `None`. [...] Is this something that the Python community is interested in? I'm willing to write the PEP
I'm definitely interested, and coincidentally I started writing my own Symbol class a week or two ago (but put it aside unfinished due to other commitments) but honestly after four months of the assignment expression PEP I'm suffering from battle fatigue. It would be nice to have a break from controversial PEPs and catch my breath :-) -- Steve
On Fri, 6 Jul 2018 at 07:30, Steven D'Aprano <steve@pearwood.info> wrote:
On Thu, Jul 05, 2018 at 02:38:47PM -0500, Flavio Curella wrote:
More than once I've found myself wanting to create a 'sentinel' value. The most common use case is to differentiate between an argument that has not been provided, and an argument provided with the value `None`. [...] Is this something that the Python community is interested in? I'm willing to write the PEP
I'm definitely interested, and coincidentally I started writing my own Symbol class a week or two ago (but put it aside unfinished due to other commitments) but honestly after four months of the assignment expression PEP I'm suffering from battle fatigue. It would be nice to have a break from controversial PEPs and catch my breath :-)
unittest.mock includes a sentinel object, with nice repr.
from unittest.mock import sentinel sentinel.Foo sentinel.Foo
Michael
-- Steve _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- http://www.michaelfoord.co.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html
Historically this has always been achieved by using: _default = object() def fun(arg=_default): if arg is not _default: .... ...which does its job just fine. If you need something like this you're typically a medium/advanced Python user so you either already know about it or you'll find the solution on Google pretty quickly. A dedicated sentinel()/Sentinel/... thingy would just be more "official", but at the end of the day it would achieve exactly the same thing by adding more complexity to the language for no practical benefit (and I seriously think Python is getting too big). -1 On Thu, Jul 5, 2018 at 9:39 PM Flavio Curella <flavio.curella@gmail.com> wrote:
More than once I've found myself wanting to create a 'sentinel' value. The most common use case is to differentiate between an argument that has not been provided, and an argument provided with the value `None`.
This would be solvable by implementing something similar to what JavaScript calls [`Symbol`]( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Obj... ).
This could be implemented as a 3rd-party library, but there won't be a way to have ['Global' Symbols]( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Obj... )
Furthermore, without a common implementation in the std library, various Python libraries had to write their own implementations, which all differs in functionality and behavior.
Is this something that the Python community is interested in? I'm willing to write the PEP
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Giampaolo - http://grodola.blogspot.com
@Nathaniel Smith:
I think the name "symbol" here is pretty confusing. It comes originally from Lisp The thing you're talking about is what Python devs call a "sentinel" object.
Thank you for clarifying. I don't know much about Lisp, and I definitely appreciate the historical context that you provided :) I will refer to the new proposed type as `sentinel` from now on. @Michael Foord
unittest.mock includes a sentinel object, with nice repr.
Thank you! I didn't think of looking in the mock library. This is one step closer, but it still have a few considerations: 1. It doesn't follow the same behaviour as the JS spec. But honestly, we don't have to. 2. It's kinda weird to have to import `unittest.<something>` in code that's not tests. But I think it's just because I'm not used to see it. @Giampaolo Rodola'
Historically this has always been achieved by using [...] which does its job just fine.
The main issue with that approach is that you won't get a nice repr
adding more complexity to the language for no practical benefit
I'm not following. The Python language won't be modified. I'm proposing adding the new type _purely_ for practical benefit. I think this thread can be resolved as 'used unittest.mock.sentinel'. It doesn't have 'global sentinels', but I'm not convinced they are actually necessary, since `mock.sentinel` objects with the same name compare as equal. Thanks to Nathaniel, I now understand that JS has global symbols for historical reasons that we don't have, and I'm not convinced of their usefulness. Thank you everybody for you valuable feedback! I really appreciate your time helping me thinking this through :)
Thanks for an interesting discussion. I would also urge people to limit the use of such sentinels for cases where it is *really* important to distinguish between, say, f(None) and f(). In most cases using def f(arg=None) is fine, and often it is even a virtue that passing None or omitting an argument has exactly the same meaning. (I do know there a cases where this doesn't apply -- I just think they ought to be fairly unusual.) On Fri, Jul 6, 2018 at 8:21 AM Flavio Curella <flavio.curella@gmail.com> wrote:
@Nathaniel Smith:
I think the name "symbol" here is pretty confusing. It comes originally from Lisp The thing you're talking about is what Python devs call a "sentinel" object.
Thank you for clarifying. I don't know much about Lisp, and I definitely appreciate the historical context that you provided :)
I will refer to the new proposed type as `sentinel` from now on.
@Michael Foord
unittest.mock includes a sentinel object, with nice repr.
Thank you! I didn't think of looking in the mock library.
This is one step closer, but it still have a few considerations: 1. It doesn't follow the same behaviour as the JS spec. But honestly, we don't have to. 2. It's kinda weird to have to import `unittest.<something>` in code that's not tests. But I think it's just because I'm not used to see it.
@Giampaolo Rodola'
Historically this has always been achieved by using [...] which does its job just fine.
The main issue with that approach is that you won't get a nice repr
adding more complexity to the language for no practical benefit
I'm not following. The Python language won't be modified. I'm proposing adding the new type _purely_ for practical benefit.
I think this thread can be resolved as 'used unittest.mock.sentinel'. It doesn't have 'global sentinels', but I'm not convinced they are actually necessary, since `mock.sentinel` objects with the same name compare as equal. Thanks to Nathaniel, I now understand that JS has global symbols for historical reasons that we don't have, and I'm not convinced of their usefulness.
Thank you everybody for you valuable feedback! I really appreciate your time helping me thinking this through :)
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido)
Guido van Rossum wrote on 7/6/18 08:31:
Thanks for an interesting discussion. I would also urge people to limit the use of such sentinels for cases where it is *really* important to distinguish between, say, f(None) and f(). In most cases using def f(arg=None) is fine, and often it is even a virtue that passing None or omitting an argument has exactly the same meaning. (I do know there a cases where this doesn't apply -- I just think they ought to be fairly unusual.)
One of the most common places I use a non-None sentinel is when None is a valid value in a dictionary: _missing = object() if mydict.get('foo', _missing) is _missing: # it ain't there I generally don't feel like a more complicated repr is valuable here, so I haven't really wanted a built-in sentinel in a long time. My search fu is weak today, but I'm pretty sure I suggested such a thing (and was rightly persuaded against it) many years ago. what-goes-around-comes-around-ly y'rs, -Barry
On Wed, Jul 11, 2018 at 6:53 AM, Barry Warsaw <barry@python.org> wrote:
Guido van Rossum wrote on 7/6/18 08:31:
Thanks for an interesting discussion. I would also urge people to limit the use of such sentinels for cases where it is *really* important to distinguish between, say, f(None) and f(). In most cases using def f(arg=None) is fine, and often it is even a virtue that passing None or omitting an argument has exactly the same meaning. (I do know there a cases where this doesn't apply -- I just think they ought to be fairly unusual.)
One of the most common places I use a non-None sentinel is when None is a valid value in a dictionary:
_missing = object()
if mydict.get('foo', _missing) is _missing: # it ain't there
I generally don't feel like a more complicated repr is valuable here, so I haven't really wanted a built-in sentinel in a long time. My search fu is weak today, but I'm pretty sure I suggested such a thing (and was rightly persuaded against it) many years ago.
For that specific example, I would just use: try: mydict['foo'] except KeyError: # it ain't there ChrisA
On 7/6/2018 11:20 AM, Flavio Curella wrote:
I think this thread can be resolved as 'used unittest.mock.sentinel'. It doesn't have 'global sentinels', but I'm not convinced they are actually necessary, since `mock.sentinel` objects with the same name compare as equal. Thanks to Nathaniel, I now understand that JS has global symbols for historical reasons that we don't have, and I'm not convinced of their usefulness.
Do all Python distributions ship with unittest.mock? I see to recall that Debian and/or Ubuntu strips out part of the normal distribution. For example, dataclasses.py has a sentinel, and it includes some code to get a more helpful repr. It would make sense to re-use the unittest.mock.sentinel code, but not if that code isn't always guaranteed to be present. Eric
On Fri, 6 Jul 2018 at 09:24 Eric V. Smith <eric@trueblade.com> wrote:
On 7/6/2018 11:20 AM, Flavio Curella wrote:
I think this thread can be resolved as 'used unittest.mock.sentinel'. It doesn't have 'global sentinels', but I'm not convinced they are actually necessary, since `mock.sentinel` objects with the same name compare as equal. Thanks to Nathaniel, I now understand that JS has global symbols for historical reasons that we don't have, and I'm not convinced of their usefulness.
Do all Python distributions ship with unittest.mock? I see to recall that Debian and/or Ubuntu strips out part of the normal distribution.
It's usually tkinter and such, not unittest stuff from my understanding.
For example, dataclasses.py has a sentinel, and it includes some code to get a more helpful repr. It would make sense to re-use the unittest.mock.sentinel code, but not if that code isn't always guaranteed to be present.
Would it make sense to abstract this out to the 'types' to have a single 'types.sentinel' object for those rare cases that Guido pointed out?
On 7/9/2018 5:01 PM, Brett Cannon wrote:
On Fri, 6 Jul 2018 at 09:24 Eric V. Smith <eric@trueblade.com <mailto:eric@trueblade.com>> wrote:
On 7/6/2018 11:20 AM, Flavio Curella wrote: > I think this thread can be resolved as 'used unittest.mock.sentinel'. It > doesn't have 'global sentinels', but I'm not convinced they are actually > necessary, since `mock.sentinel` objects with the same name compare as > equal. Thanks to Nathaniel, I now understand that JS has global symbols > for historical reasons that we don't have, and I'm not convinced of > their usefulness.
Do all Python distributions ship with unittest.mock? I see to recall that Debian and/or Ubuntu strips out part of the normal distribution.
It's usually tkinter and such, not unittest stuff from my understanding.
Good to know. Thanks.
For example, dataclasses.py has a sentinel, and it includes some code to get a more helpful repr. It would make sense to re-use the unittest.mock.sentinel code, but not if that code isn't always guaranteed to be present.
Would it make sense to abstract this out to the 'types' to have a single 'types.sentinel' object for those rare cases that Guido pointed out?
I think so. I'd hate to import unittest.mock just to get a sentinel object for dataclasses. Eric
participants (11)
-
Barry Warsaw
-
Brett Cannon
-
Chris Angelico
-
Ed Kellett
-
Eric V. Smith
-
Flavio Curella
-
Giampaolo Rodola'
-
Guido van Rossum
-
Joseph Jevnik
-
Michael Foord
-
Steven D'Aprano