![]() |
|
|
|
#1 |
|
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? Can there be two None objects in interpreter's memory? Is testing for identity of some variable with None safe? Does language guarantee that? Or is it just property of implementation? Regards, mk mk |
|
|
|
|
#2 |
|
Posts: n/a
|
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. > ..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 Stefan Stefan Behnel |
|
|
|
#3 |
|
Posts: n/a
|
* 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? > > Can there be two None objects in interpreter's memory? Is testing for > identity of some variable with None safe? Does language guarantee that? > Or is it just property of implementation? As I understand it, 'is' will always work and will always be efficient (it just checks the variable's type), while '==' can depend on the implementation of equality checking for the other operand's class. Cheers & hth., - Alf Alf P. Steinbach |
|
|
|
#4 |
|
Posts: n/a
|
On Nov 7, 12:35*am, "Alf P. Steinbach" <al...@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) John Machin |
|
|
|
#5 |
|
Posts: n/a
|
Alf P. Steinbach wrote:
> As I understand it, 'is' will always work and will always be efficient > (it just checks the variable's type), while '==' can depend on the > implementation of equality checking for the other operand's class. "== None" makes sense, for instance, in the context of the SQLAlchemy sql construction layer, where the underlying machinery defines __eq__() / __ne__() and generates the appropriate 'IS NULL' SQL code when appropriate. Marco Mariani |
|
|
|
#6 |
|
Posts: n/a
|
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 mk |
|
|
|
#7 |
|
Posts: n/a
|
* John Machin:
> On Nov 7, 12:35 am, "Alf P. Steinbach" <al...@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 Alf P. Steinbach |
|
|
|
#8 |
|
Posts: n/a
|
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 Marco Mariani |
|
|
|
#9 |
|
Posts: n/a
|
* 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 Alf P. Steinbach |
|
|
|
#10 |
|
Posts: n/a
|
On Fri, 06 Nov 2009 08:54:53 -0800, Alf P. Steinbach <>
wrote: > But wow. That's pretty hare-brained: dynamic allocation for every stored > value outside the cache range, needless extra indirection for every > operation. > Perhaps I'm not understanding this thread at all but how is dynamic allocation hare-brained, and what's the 'needless extra indirection'? -- Rami Chowdhury "Never attribute to malice that which can be attributed to stupidity" -- Hanlon's Razor 408-597-7068 (US) / 07875-841-046 (UK) / 0189-245544 (BD) Rami Chowdhury |
|