From: mk on
Stefan Behnel wrote:
> mk, 06.11.2009 14:20:
>> Some claim that one should test for None using:
>>
>> if x is None:
>
> Which is the correct and safe way of doing it.

ok

>> ..but the standard equality which is theoretically safer works as well:
>>
>> if x == None:
>
> Absolutely not safe, think of
>
> class Test(object):
> def __eq__(self, other):
> return other == None
>
> print Test() == None, Test() is None

Err, I don't want to sound daft, but what is wrong in this example? It
should work as expected:

>>> class Test(object):
.... def __eq__(self, other):
.... return other == None
....
>>> Test() is None
False
>>> Test() == None
True

My interpretation of 1st call is that it is correct: instance Test() is
not None (in terms of identity), but it happens to have value equal to
None (2nd call).

Or perhaps your example was supposed to show that I should test for
identity with None, not for value with None?

That, however, opens a can of worms, sort of: whether one should compare
Test() for identity with None or for value with None depends on what
programmer meant at the moment.

Regards,
mk





From: Daniel Fetchinson on
> Some claim that one should test for None using:
>
> if x is None:
>
> ..but the standard equality which is theoretically safer works as well:
>
> if x == None:
>
> So, which one is recommended?

It depends on what you want to do. There is no single answer to your
question, until you tell us what your context is.

The None object in python is a singleton. If you want to check whether
a given object is this singleton None object (note that this is
unambiguous, it either occupies the same address in memory as the
singleton None or it doesn't) then you should use 'x is None'.

If, however you want to test for equality, you should use 'x == None'.
An object 'x' may implement equality checks in a funny way and it may
be that 'x == None' is True although 'x is None' is False. But it may
be that this is exactly what you want, because the author of the
object 'x' intentionally has written the equality check code to make
this so. In this case you need 'x == None'.

So unless you tell us in what context you are asking this question,
there is no single answer to it.

Cheers,
Daniel



--
Psss, psss, put it down! - http://www.cafepress.com/putitdown
From: Alf P. Steinbach on
* John Machin:
> On Nov 7, 12:35 am, "Alf P. Steinbach" <al...(a)start.no> wrote:
>> * mk:
>>
>>> Hello,
>>> Some claim that one should test for None using:
>>> if x is None:
>>> ..but the standard equality which is theoretically safer works as well:
>>> if x == None:
>>> So, which one is recommended?
>>
>> As I understand it, 'is' will always work and will always be efficient (it just
>> checks the variable's type),
>
> It doesn't check the type.
> It doesn't need to. (x is y) is true if x
> and y are the same object. If that is so, then of course (type(x) is
> type(y)) is true, and if not so, their types are irrelevant. "is"
> testing is very efficient in the CPython implementation: addressof(x)
> == addressof(y)

Maybe.

I imagined it wouldn't waste additional space for e.g. (Python 2.x) int values,
but just use the same space as used for pointer in the case of e.g. string, in
which case it would have to check the type -- an integer can very easily have
the same bitpattern as a pointer residing there.

If you imagine that instead, for an integer variable x it stores the integer
value in the variable in some other place than ordinarily used for pointer, and
let the pointer point to that place in the same variable, then without checking
type the 'is' operator should report false for 'x = 3; y = 3; x is y', but it
doesn't with my Python installation, so if it doesn't check the type then even
this half-measure (just somewhat wasteful of space) optimization isn't there.

In short, you're saying that there is an extreme inefficiency with every integer
dynamically allocated /plus/, upon production of an integer by e.g. + or *,
inefficiently finding the previously allocated integer of that value and
pointing there, sort of piling inefficiency on top of inefficiency, which is
absurd but I have seen absurd things before so it's not completely unbelievable.

I hope someone else can comment on these implications of your statement.


Cheers,

- Alf
From: Marco Mariani on
Alf P. Steinbach wrote:

> If you imagine that instead, for an integer variable x it stores the
> integer value in the variable in some other place than ordinarily used
> for pointer, and let the pointer point to that place in the same
> variable, then without checking type the 'is' operator should report
> false for 'x = 3; y = 3; x is y', but it doesn't with my Python

Yes, CPython caches a handful of small, "commonly used" integers, and
creates objects for them upon startup. Using "x is y" with integers
makes no sense and has no guaranteed behaviour AFAIK

> In short, you're saying that there is an extreme inefficiency with every
> integer dynamically allocated /plus/, upon production of an integer by
> e.g. + or *, inefficiently finding the previously allocated integer of
> that value and pointing there,

no, it doesn't "point there":

>>>> a=1E6
>>>> a is 1E6
> False
>>>> a=100
>>>> a is 100
> True
From: Alf P. Steinbach on
* Marco Mariani:
> Alf P. Steinbach wrote:
>
>> If you imagine that instead, for an integer variable x it stores the
>> integer value in the variable in some other place than ordinarily used
>> for pointer, and let the pointer point to that place in the same
>> variable, then without checking type the 'is' operator should report
>> false for 'x = 3; y = 3; x is y', but it doesn't with my Python
>
> Yes, CPython caches a handful of small, "commonly used" integers, and
> creates objects for them upon startup. Using "x is y" with integers
> makes no sense and has no guaranteed behaviour AFAIK
>
>> In short, you're saying that there is an extreme inefficiency with
>> every integer dynamically allocated /plus/, upon production of an
>> integer by e.g. + or *, inefficiently finding the previously allocated
>> integer of that value and pointing there,
>
> no, it doesn't "point there":
>
>>>>> a=1E6
>>>>> a is 1E6
>> False
>>>>> a=100
>>>>> a is 100
>> True

I stand corrected on that issue, I didn't think of cache for small values.

On my CPython 3.1.1 the cache seems to support integer values -5 to +256,
inclusive, apparently using 16 bytes of storage per value (this last assuming
id() just returns the address).

But wow. That's pretty hare-brained: dynamic allocation for every stored value
outside the cache range, needless extra indirection for every operation.

Even Microsoft COM managed to get this right.

On the positive side, except that it would probably break every C module (I
don't know), in consultant speak that's definitely a potential for improvement. :-p


Cheers,

- Alf