Collin Funk wrote:
> One thing that annoys me personally
> is comparing to none using "!=" instead of "is not". This is
> recommended against in PEP 8, "Comparisons to singletons like None
> should always be done with is or is not, never the equality
> operators." [1].

Dima Pasechnik wrote:
> The pythonic way is
> 
>     mode is not None
> 
> rather than 
> 
>     mode != None
> 
> (the reason is None is an object)

Summarizing the arguments for "is not None":
  1- Clarity and readability, best practice, PEP 8.
  2- Identity comparison vs. value comparison.
  3- None is a singleton.
  4- Prevents wrong results if an __eq__ method has been incorrectly coded.

Here's my take on it.

1- is clearly subjective. Clarity is context dependent. Etc.
2- Yes, https://docs.python.org/3.12/reference/expressions.html#comparisons
   clearly explains the difference between == and 'is'.
   (It's more or less like the difference between EQUAL and EQ in Lisp.)
3- None is a singleton, but it nonetheless supports both == and 'is'. So,
   this is a weak argument.
4- This is one of the weakest possible arguments.

The style warnings about "!= None" in pycodestyle and/or pylint are
relativized by this warning in Python itself:

  >>> '' != None
  True
  >>> '' is not None
  <stdin>:1: SyntaxWarning: "is not" with a literal. Did you mean "!="?
  True

So, if Python itself warns about some code that follows PEP 8...
it means that we need to think carefully, rather than blindly apply
that PEP 8 rule.

I think a better rule, in particular in the context of gnulib-tool.py,
is to observe that each variable has a certain set of possible values
(even though this set of values is not explicitly stated in the source
code), and with this set of possible values comes a comparison operator.

So, what I mean is:

  * If a variable can only contain objects like GLModule instances or None,
    then 'is' (pointer comparison) is the right choice for this variable.

  * If a variable can only contain strings or None, then '==' (value
    comparison) is the right choice for this variable, since comparing
    strings with 'is' is unreliable:

      >>> x = "ab"
      >>> y = "ab"
      >>> x is y
      True
      
      >>> x = "abc"[:2]
      >>> y = "abx"[:2]
      >>> x is y
      False

  * If a variable can only contain a list or None, then '==' (value comparison)
    is the right choice for this variable.

    >>> ["a"] == ["a"]
    True
    >>> ["a"] is ["a"]
    False

So, depending on the variable:
   mode != None                       OK
   modules != None                    OK
   module != None                     not OK, better write:   module is not None

Bruno




Reply via email to