On 16Jan2016 22:42, Alex Kleider <aklei...@sonic.net> wrote:
On 2016-01-16 18:02, Cameron Simpson wrote:
much like writing a function "def f(x, y=None)"; None is a sentinel
value - specially recognised as nor in the normal domain for that
value.

Can you please clarify the last bit:
"specially recognised as nor in the normal domain for that value."

s/nor/not/

The domain of a function (or value) is the set of valid values it may take. The range is the set of values it may produce.

A sentinel value is a special value you may encounter in a data set (or as a value) which is _not_ part of the normal domain; often it indicates the end of a sequence (hence the name, like a border guard). In Python the special value None is often used as a sentinel value. Since all names have _some_ value, if you need to indicate that this name "isn't set" or "doesn't specify a valid value", you need a sentinal value, often "None".

So the common idiom for default values in Python function definitions:

 def func(a, b, c=None):
   if c is None:
     c = default-value-for-c
   ...

indicates that the parameters "a" and "b must be supplied, and "c" is optional. If not supplied it will have the value "None". This is a sentinel value so that "func" can distinguish a valid value from a value not supplied.

You can also use them to indicate the end of data in some sense. If you're looking at a text file as lines of printable characters, the newline character at the end of the line could be considered a sentinel. Also consider a Queue: there's no notion of "closed" in the stdlib version, so one might put a None on the queue to indicate to the consumer that there will be no more items.

It isn't always None. Sometimes you may want to pass None as normal data, or you have no control over what is passed around. In that case you might need to make a unique sentinel value entirely for your object. The normal way to do this is simply to make a new object:

 sentinel = object()

This is a minimal Python object which nobody else is using. Its value is nothing special (or even meaningful), so you merely want to check whether what you've got is that particular object, using "is". Untested example sketch:

 class SomethingLikeAQueue:

   def __init__(self,......):
     self.things = []
     # private value to use as a sentinel, unique per instance
     self._sentinel = object()
     ... whatever else ...

   def put(self, value):
     # public method to put a new value
     if value is self._sentinel:
       raise ValueError("you may not put the sentinel value")
     self._put(value)

   def _put(self, value):
     # private method accepting any value including the sentinel
# we will use receipt of the sentinel to process the things and stop # further acceptance of more things
     if value is self._sentinel:
       things = self.things
       self.things = None  # will make the .append blow up
       ... process things here maybe ...
     else:
       things.append(value)

   def close(self):
     # send the sentinel to indicate no more things
     self._put(self._sentinel)

Cheers,
Cameron Simpson <c...@zip.com.au>
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

Reply via email to