Test None for an object that does not implement ==

Discussion in 'Python' started by GZ, Dec 25, 2011.

  1. GZ

    GZ Guest

    Hi,

    I run into a weird problem. I have a piece of code that looks like the
    following:

    f(...., a=None, c=None):
    assert (a==None)==(c==None)


    The problem is that == is not implemented sometimes for values in a
    and c, causing an exception NotImplementedError.

    I ended up doing assert (not a)==(not c), but I think this code has
    other issues, for example, when a=[] and c=['a'], the assertion will
    fail, although a is not None.

    So how do I reliably test if a value is None or not?

    Thanks,
    gz
    GZ, Dec 25, 2011
    #1
    1. Advertising

  2. GZ

    Paul Rubin Guest

    GZ <> writes:
    > assert (a==None)==(c==None)...
    > So how do I reliably test if a value is None or not?


    Equality is the wrong comparison to start with. Use "a is None".
    Paul Rubin, Dec 25, 2011
    #2
    1. Advertising

  3. GZ

    Nobody Guest

    On Sat, 24 Dec 2011 23:09:50 -0800, GZ wrote:

    > I run into a weird problem. I have a piece of code that looks like the
    > following:
    >
    > f(...., a=None, c=None):
    > assert (a==None)==(c==None)
    >
    >
    > The problem is that == is not implemented sometimes for values in a
    > and c, causing an exception NotImplementedError.


    I have no idea how that can happen. If a.__eq__(None) returns
    NotImplemented, the interpreter should flip the test and perform the
    equivalent of None.__eq__(a), which will return False.

    > So how do I reliably test if a value is None or not?


    As Paul says, use "is" to check whether a value _is_ None. Checking for
    equality is almost certainly the wrong thing to do; nothing should compare
    equal to None except for None itself, so "x is None" and "x == None"
    shouldn't produce different results unless there's a bug in the comparison
    method.
    Nobody, Dec 25, 2011
    #3
  4. GZ

    Lie Ryan Guest

    On 12/25/2011 08:38 PM, Nobody wrote:

    > nothing should compare equal to None except for None itself, so "x is None"
    > and "x == None" shouldn't produce different results unless there's a
    > bug in the comparison method.


    not necessarily, for example:

    import random
    class OddClass:
    def __eq__(self, other):
    return [True, False][random.randint(0, 1)]

    x = OddClass()
    print x == None
    print x == None
    print x == None
    print x == None
    print x == None


    Now, whether doing something like that is advisable or not, that's a
    different question; however nothing in python states that you couldn't
    have something that compare equal to None whether there is a bug or not
    in the comparison method.
    Lie Ryan, Dec 25, 2011
    #4
  5. GZ

    Roy Smith Guest

    In article <>,
    Lie Ryan <> wrote:

    > Now, whether doing something like that is advisable or not, that's a
    > different question; however nothing in python states that you couldn't
    > have something that compare equal to None whether there is a bug or not
    > in the comparison method.


    Just for fun, I tried playing around with subclassing NoneType and
    writing an __eq__ for my subclass. Turns out, you can't do that:

    Traceback (most recent call last):
    File "./none.py", line 5, in <module>
    class Nihil(NoneType):
    TypeError: Error when calling the metaclass bases
    type 'NoneType' is not an acceptable base type
    Roy Smith, Dec 25, 2011
    #5
  6. On Mon, Dec 26, 2011 at 12:17 AM, Roy Smith <> wrote:
    > Just for fun, I tried playing around with subclassing NoneType and
    > writing an __eq__ for my subclass.  Turns out, you can't do that:
    >
    > Traceback (most recent call last):
    >  File "./none.py", line 5, in <module>
    >    class Nihil(NoneType):
    > TypeError: Error when calling the metaclass bases
    >    type 'NoneType' is not an acceptable base type


    Yes; unfortunately quite a few Python built-in classes can't be
    subclassed. It's an unfortunate fact of implementation, I think,
    rather than a deliberate rule.

    But then, what would you ever need to subclass None for, other than
    toys and testing?

    ChrisA
    Chris Angelico, Dec 25, 2011
    #6
  7. On Mon, 26 Dec 2011 00:35:46 +1100, Chris Angelico wrote:

    [...]
    >> TypeError: Error when calling the metaclass bases
    >>    type 'NoneType' is not an acceptable base type

    >
    > Yes; unfortunately quite a few Python built-in classes can't be
    > subclassed.



    I can't think of any other un-subclassable classes other than NoneType.
    Which ones are you thinking of?



    --
    Steven
    Steven D'Aprano, Dec 25, 2011
    #7
  8. On Mon, Dec 26, 2011 at 12:48 AM, Steven D'Aprano
    <> wrote:
    > I can't think of any other un-subclassable classes other than NoneType.
    > Which ones are you thinking of?


    I don't remember, but it was mentioned in a thread a little while ago.
    Experimentation shows that 'bool' is one of them, though. This may
    shed some light:

    >>> class Foo(type(iter)):

    pass

    Traceback (most recent call last):
    File "<pyshell#103>", line 1, in <module>
    class Foo(type(iter)):
    TypeError: type 'builtin_function_or_method' is not an acceptable base type

    I think there are certain types that are actually not implemented as
    classes, and hence cannot be subclassed. This is almost certainly an
    implementation detail though; my testing was done in Py3.2 (on Windows
    fwiw).

    ChrisA
    Chris Angelico, Dec 25, 2011
    #8
  9. GZ

    Roy Smith Guest

    In article <>,
    Chris Angelico <> wrote:

    > On Mon, Dec 26, 2011 at 12:17 AM, Roy Smith <> wrote:
    > > Just for fun, I tried playing around with subclassing NoneType and
    > > writing an __eq__ for my subclass.  Turns out, you can't do that:
    > >
    > > Traceback (most recent call last):
    > >  File "./none.py", line 5, in <module>
    > >    class Nihil(NoneType):
    > > TypeError: Error when calling the metaclass bases
    > >    type 'NoneType' is not an acceptable base type

    >
    > Yes; unfortunately quite a few Python built-in classes can't be
    > subclassed. It's an unfortunate fact of implementation, I think,
    > rather than a deliberate rule.
    >
    > But then, what would you ever need to subclass None for, other than
    > toys and testing?


    You might be to differentiate between temporary and permanent failures.
    Let's say you have a WidgetPool, containing Widgets of various classes.

    class WidgetPool:
    def get_widget(class_name):
    """Return a Widget of a given class. If there are no such
    Widgets available, returns None."""
    [...]

    You might want to return a None subclass to signify, "No such Widgets
    are currently available, but they might be if you try again in a little
    while", as opposed to "No such Widgets will ever be available".

    If you were designing the interface from scratch, you would probably
    represent that with an exception hierarchy. However, if this was an old
    interface that you were modifying, this might be a way to return a
    richer failure indication for new clients without breaking backwards
    compatibility for existing code.

    Of course, the existing code would probably be using "is None" tests,
    and break anyway. But at least that's a plausible scenario for None
    subclasses.
    Roy Smith, Dec 25, 2011
    #9
  10. On Mon, Dec 26, 2011 at 1:13 AM, Roy Smith <> wrote:
    > If you were designing the interface from scratch, you would probably
    > represent that with an exception hierarchy


    Or possibly with "returns a False value", giving the option of None
    for none available, False for none will ever be available. Of course,
    you then have to guarantee that your live return values will always
    boolify as True.

    ChrisA
    Chris Angelico, Dec 25, 2011
    #10
  11. GZ

    Lie Ryan Guest

    On 12/26/2011 01:13 AM, Roy Smith wrote:
    > In article<>,
    > Chris Angelico<> wrote:
    >
    >> On Mon, Dec 26, 2011 at 12:17 AM, Roy Smith<> wrote:
    >>> Just for fun, I tried playing around with subclassing NoneType and
    >>> writing an __eq__ for my subclass. Turns out, you can't do that:
    >>>
    >>> Traceback (most recent call last):
    >>> File "./none.py", line 5, in<module>
    >>> class Nihil(NoneType):
    >>> TypeError: Error when calling the metaclass bases
    >>> type 'NoneType' is not an acceptable base type

    >>
    >> Yes; unfortunately quite a few Python built-in classes can't be
    >> subclassed. It's an unfortunate fact of implementation, I think,
    >> rather than a deliberate rule.
    >>
    >> But then, what would you ever need to subclass None for, other than
    >> toys and testing?

    >
    > You might be to differentiate between temporary and permanent failures.
    > Let's say you have a WidgetPool, containing Widgets of various classes.
    >
    > class WidgetPool:
    > def get_widget(class_name):
    > """Return a Widget of a given class. If there are no such
    > Widgets available, returns None."""
    > [...]
    >
    > You might want to return a None subclass to signify, "No such Widgets
    > are currently available, but they might be if you try again in a little
    > while", as opposed to "No such Widgets will ever be available".
    >
    > If you were designing the interface from scratch, you would probably
    > represent that with an exception hierarchy. However, if this was an old
    > interface that you were modifying, this might be a way to return a
    > richer failure indication for new clients without breaking backwards
    > compatibility for existing code.
    >
    > Of course, the existing code would probably be using "is None" tests,
    > and break anyway. But at least that's a plausible scenario for None
    > subclasses.


    That scenario doesn't actually need subclassing if you duck type.
    Lie Ryan, Dec 25, 2011
    #11
  12. > At first glance this looked like it should be a simple boolean "and", but
    > then I realized that when a and c are both unequal to None, the result would
    > also be True. This implies the logical approach would be exclusive-or (^).


    Among booleans, "!=" is exclusive or and "==" is its negation. I don't
    see the point of complicating the formula to use ^.

    (related: <= is implication. Which is sad, because the arrow points
    the wrong way!)

    The issue here is that "== None" is being used instead of "is None",
    but I believe that's been covered. Your response doesn't include it,
    so maybe it's worth restating.

    -- Devin

    On Sun, Dec 25, 2011 at 6:45 PM, Larry Hudson <> wrote:
    > On 12/24/2011 11:09 PM, GZ wrote:
    >>
    >> Hi,
    >>
    >> I run into a weird problem. I have a piece of code that looks like the
    >> following:
    >>
    >> f(...., a=None, c=None):
    >>     assert  (a==None)==(c==None)
    >>

    > <...>
    >
    > At first glance this looked like it should be a simple boolean "and", but
    > then I realized that when a and c are both unequal to None, the result would
    > also be True.  This implies the logical approach would be exclusive-or (^).
    >  Try this expression:
    >
    >     not ((a==None) ^ (c==None))
    >
    > OTOH, if what you really want is simply to check that both are None (my
    > first impression), then it's simply:
    >
    >     (a==None) and (c==None)
    >
    > Most of the replies you're getting here seem unnecessarily complicated.
    >
    >> Thanks,
    >> gz

    >
    >
    >    -=- Larry -=-
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    Devin Jeanpierre, Dec 26, 2011
    #12
  13. GZ

    Roy Smith Guest

    In article <>,
    Devin Jeanpierre <> wrote:

    > The issue here is that "== None" is being used instead of "is None",
    > but I believe that's been covered. Your response doesn't include it,
    > so maybe it's worth restating.


    Which of course leads to a SillyPEP for a new keyword, "are", which
    would allow you to write:

    >>> a and c are None


    instead of the much more verbose

    >>> a is None and c is None
    Roy Smith, Dec 26, 2011
    #13
  14. On Sun, 25 Dec 2011 15:45:10 -0800, Larry Hudson wrote:

    > On 12/24/2011 11:09 PM, GZ wrote:
    >> Hi,
    >>
    >> I run into a weird problem. I have a piece of code that looks like the
    >> following:
    >>
    >> f(...., a=None, c=None):
    >> assert (a==None)==(c==None)
    >>

    > <...>
    >
    > At first glance this looked like it should be a simple boolean "and",
    > but then I realized that when a and c are both unequal to None, the
    > result would also be True. This implies the logical approach would be
    > exclusive-or (^). Try this expression:
    >
    > not ((a==None) ^ (c==None))


    ^ is *bitwise* xor, not boolean xor. Python doesn't offer boolean xor
    directly, although != comes close.


    > OTOH, if what you really want is simply to check that both are None (my
    > first impression), then it's simply:
    >
    > (a==None) and (c==None)


    Replace == with 'is'.

    > Most of the replies you're getting here seem unnecessarily complicated.


    == is a more complicated operator than the 'is' operator. That's why the
    is operator is to be preferred when testing for None -- it is guaranteed
    to do the right thing, while == is not.


    --
    Steven
    Steven D'Aprano, Dec 26, 2011
    #14
  15. > Which of course leads to a SillyPEP for a new keyword, "are", which
    > would allow you to write:
    >
    >>>> a and c are None

    >
    > instead of the much more verbose
    >
    >>>> a is None and c is None


    How about:

    >>> a is b is None


    ;)

    -- Devin

    On Sun, Dec 25, 2011 at 7:27 PM, Roy Smith <> wrote:
    > In article <>,
    >  Devin Jeanpierre <> wrote:
    >
    >> The issue here is that "== None" is being used instead of "is None",
    >> but I believe that's been covered. Your response doesn't include it,
    >> so maybe it's worth restating.

    >
    > Which of course leads to a SillyPEP for a new keyword, "are", which
    > would allow you to write:
    >
    >>>> a and c are None

    >
    > instead of the much more verbose
    >
    >>>> a is None and c is None

    > --
    > http://mail.python.org/mailman/listinfo/python-list
    Devin Jeanpierre, Dec 26, 2011
    #15
  16. GZ

    Ian Kelly Guest

    On Sun, Dec 25, 2011 at 2:38 AM, Nobody <> wrote:
    > On Sat, 24 Dec 2011 23:09:50 -0800, GZ wrote:
    >
    >> I run into a weird problem. I have a piece of code that looks like the
    >> following:
    >>
    >> f(...., a=None, c=None):
    >>     assert  (a==None)==(c==None)
    >>
    >>
    >> The problem is that == is not implemented sometimes for values in a
    >> and c, causing an exception NotImplementedError.

    >
    > I have no idea how that can happen. If a.__eq__(None) returns
    > NotImplemented, the interpreter should flip the test and perform the
    > equivalent of None.__eq__(a), which will return False.


    Maybe the class has a misbehaved __eq__ that raises
    NotImplementedError directly instead of returning NotImplemented.
    Ian Kelly, Dec 26, 2011
    #16
  17. GZ

    Ethan Furman Guest

    Nobody wrote:
    > nothing should compare
    > equal to None except for None itself, so "x is None" and "x == None"
    > shouldn't produce different results unless there's a bug in the comparison
    > method.
    >


    Why wouldn't you want other types that can compare equal to None? It
    could be useful for a Null type to == None.

    ~Ethan~
    Ethan Furman, Dec 26, 2011
    #17
  18. GZ

    Ethan Furman Guest

    GZ wrote:
    > Hi,
    >
    > I run into a weird problem. I have a piece of code that looks like the
    > following:
    >
    > f(...., a=None, c=None):
    > assert (a==None)==(c==None)



    Um -- if you don't want a and c being passed in, why put them in the
    function signature?

    ~Ethan~
    Ethan Furman, Dec 26, 2011
    #18
  19. > Um -- if you don't want a and c being passed in, why put them in the
    > function signature?


    He wants both or neither to be passed in.

    -- Devin

    On Sun, Dec 25, 2011 at 11:27 PM, Ethan Furman <> wrote:
    > GZ wrote:
    >>
    >> Hi,
    >>
    >> I run into a weird problem. I have a piece of code that looks like the
    >> following:
    >>
    >> f(...., a=None, c=None):
    >>    assert  (a==None)==(c==None)

    >
    >
    >
    > Um -- if you don't want a and c being passed in, why put them in the
    > function signature?
    >
    > ~Ethan~
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    Devin Jeanpierre, Dec 26, 2011
    #19
  20. GZ

    Roy Smith Guest

    In article <>,
    Devin Jeanpierre <> wrote:

    > > Um -- if you don't want a and c being passed in, why put them in the
    > > function signature?

    >
    > He wants both or neither to be passed in.


    assert sum(foo is None for foo in [a, c]) % 2 == 0
    Roy Smith, Dec 26, 2011
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. alf
    Replies:
    9
    Views:
    391
  2. length power
    Replies:
    2
    Views:
    69
    Rustom Mody
    Apr 10, 2014
  3. Skip Montanaro
    Replies:
    0
    Views:
    51
    Skip Montanaro
    Apr 10, 2014
  4. Johannes Schneider

    Re: why i have the output of [None, None, None]

    Johannes Schneider, Apr 10, 2014, in forum: Python
    Replies:
    0
    Views:
    46
    Johannes Schneider
    Apr 10, 2014
  5. Terry Reedy
    Replies:
    0
    Views:
    55
    Terry Reedy
    Apr 10, 2014
Loading...

Share This Page