f

#### Difference between 'is' and '=='

Hey guys, this maybe a stupid question, but I can't seem to find the
result anywhere online. When is the right time to use 'is' and when
should we use '=='?

Thanks alot~


 0
mwql.aus (7)
3/27/2006 11:31:38 AM
comp.lang.python 77058 articles. 6 followers.

47 Replies
1050 Views

Similar Articles

[PageSpeed] 9

mwql:
>Hey guys, this maybe a stupid question, but I can't seem to find the
>result anywhere online. When is the right time to use 'is' and when
>should we use '=='?

http://docs.python.org/ref/comparisons.html

--
Ren� Pijlman

 0
3/27/2006 11:56:32 AM
mwql wrote:

> Hey guys, this maybe a stupid question, but I can't seem to find the
> result anywhere online. When is the right time to use 'is' and when
> should we use '=='?

"is" is like id(obj1) == id(obj2)

>>> 100+1 == 101
True

>>> 100+1 is 101
False

They don't have the same id. (Think of id as memory adresses.)

--

hilsen/regards Max M, Denmark

http://www.mxm.dk/

Phone:  +45 66 11 84 94
Mobile: +45 29 93 42 96

 0
maxm (304)
3/27/2006 11:56:52 AM
mwql wrote:
> Hey guys, this maybe a stupid question, but I can't seem to find the
> result anywhere online. When is the right time to use 'is' and when
> should we use '=='?
>
> Thanks alot~

'==' is the equality operator. It is used to test if two objects are
'equal'.

'is' is the identity operator, it is used to test if two
names/references point to the same object.

a = {'a': 3}
b = {'a': 3}
a == b
True
a is b
False
c = a
a is c
True

The two dictionaries a and b are equal, but are separate objects.
(Under the hood, Python uses 'id' to determine identity).

When you bind another name 'c' to point to dictionary a, they *are* the
same object - so a *is* c.

One place the 'is' operator is commonly used is when testing for None.
You only ever have one instance of 'None', so

a is None

is quicker than

a == None

(It only needs to check identity not value.)

I hope that helps.

Fuzzyman
http://www.voidspace.org.uk/python/index.shtml


 0
fuzzyman (944)
3/27/2006 12:22:01 PM
> "is" is like id(obj1) == id(obj2)
<snip>
> (Think of id as memory adresses.)

Which means that "is" comparisons in general will be faster than ==
comparisons. According to PEP8 (python programming style guidelines) you should
use 'is' when comparing to singletons like None. I take this to also include
constants and such. That allows us to take short cuts through known terrain,
such as in the massive_computations function below:

--------------------------------------------------------------
import time

class LotsOfData(object):
def __init__(self, *data):
self.data = data
def __eq__(self, o):
time.sleep(2) # time consuming computations...
return self.data == o.data

KNOWN_DATA = LotsOfData(1,2)
same_data = KNOWN_DATA
equal_data = LotsOfData(1,2)
other_data = LotsOfData(2,3)

def massive_computations(data = KNOWN_DATA):
if data is KNOWN_DATA:
elif data == KNOWN_DATA:
else:
time.sleep(10) # time consuming computations...

print "Here we go!"
print massive_computations()
print massive_computations(same_data)
print massive_computations(equal_data)
print massive_computations(other_data)
print "Done."
--------------------------------------------------------------

Cheers,
Joel

 0
3/27/2006 12:52:46 PM
In article <e08mr1$7lu$1@news.lysator.liu.se>,
Joel Hedlund <joel.hedlund@gmail.com> wrote:

> Which means that "is" comparisons in general will be faster than ==
> comparisons.

I thought that == automatically compared identify before trying to compare
the values.  Or am I thinking of some special case, like strings?

 0
roy (2295)
3/27/2006 12:59:35 PM
Roy Smith wrote:
> In article <e08mr1$7lu$1@news.lysator.liu.se>,
>  Joel Hedlund <joel.hedlund@gmail.com> wrote:
>>Which means that "is" comparisons in general will be faster than ==
>>comparisons.
>
> I thought that == automatically compared identify before trying to compare
> the values.  Or am I thinking of some special case, like strings?

You must be thinking of a special case:

>>> class A:
....   def __cmp__(self, other): return 1
....
>>> a = A()
>>> a is a
True
>>> a == a
False

-Peter


 0
peter34 (3696)
3/27/2006 1:07:01 PM
Roy Smith wrote:
> In article <e08mr1$7lu$1@news.lysator.liu.se>,
>  Joel Hedlund <joel.hedlund@gmail.com> wrote:
>
>> Which means that "is" comparisons in general will be faster than ==
>> comparisons.
>
> I thought that == automatically compared identify before trying to compare
> the values.  Or am I thinking of some special case, like strings?

Even for strings there is a performance difference:

>>> timeit.Timer("'a'=='a'").timeit()
0.26859784126281738
>>> timeit.Timer("'a' is 'a'").timeit()
0.21730494499206543

mfg
- eth

 0
ethrandil (9)
3/27/2006 1:09:52 PM
On Mon, 27 Mar 2006 14:52:46 +0200,
Joel Hedlund <joel.hedlund@gmail.com> wrote:

> ... According to PEP8 (python programming style guidelines) you should
> use 'is' when comparing to singletons like None. I take this to also
> include constants and such ...

This does *not* also mean constants and such:

Python 2.4.2 (#1, Feb 22 2006, 08:02:53)
[GCC 4.0.1 (Apple Computer, Inc. build 5247)] on darwin
>>> a = 123456789
>>> a == 123456789
True
>>> a is 123456789
False
>>>

Regards,
Dan

--
Dan Sommers
<http://www.tombstonezero.net/dan/>
"I wish people would die in alphabetical order." -- My wife, the genealogist

 0
me4 (19624)
3/27/2006 1:23:40 PM
It's really strange,

if
a = 1
b = 1
a is b ==> True

the same thing applies for strings, but not for dict, lists or tuples
I think the 'is' operator is useful for objects only, not for primitive
types,
I think I solved the mystery behind my bugged code =)


 0
mwql.aus (7)
3/27/2006 1:28:39 PM
mwql wrote:
> It's really strange,
>
> if
> a = 1
> b = 1
> a is b ==> True
>
> the same thing applies for strings

Not quite:

>>> 'abc' is 'abc'
True
>>> 'abc' is 'ab' + 'c'
False

--
Benji York

 0
benji9101 (180)
3/27/2006 1:44:33 PM
Dan Sommers wrote:
> This does *not* also mean constants and such:
>
>     Python 2.4.2 (#1, Feb 22 2006, 08:02:53)
>     [GCC 4.0.1 (Apple Computer, Inc. build 5247)] on darwin
>     >>> a = 123456789
>     >>> a == 123456789
>     True
>     >>> a is 123456789
>     False

It's strange: python seem to cache constants from 0 to 99:

for x in xrange(1000):
if not eval("%d"%x) is eval("%d"%x):
print x

for me it printed 100-999.

- eth

 0
ethrandil (9)
3/27/2006 1:49:05 PM
mwql wrote:

> It's really strange,
>
> if
> a = 1
> b = 1
> a is b ==> True
>
> the same thing applies for strings, but not for dict, lists or tuples
> I think the 'is' operator is useful for objects only, not for primitive
> types,
> I think I solved the mystery behind my bugged code =)

The reason that "is" works for small numbers is that these are cached for
performance reasons. Try

>>> a = 1000000
>>> b = 1000000
>>> a is b
False

So - your conclusion is basically right: use is on (complex) objects, not on
numbers and strings and other built-ins. The exception from the rule is
None - that should only exist once, so

foo is not None

is considered better style than foo == None.

Diez

 0
deets (3351)
3/27/2006 2:04:07 PM
Em Seg, 2006-03-27 às 08:23 -0500, Dan Sommers escreveu:
> On Mon, 27 Mar 2006 14:52:46 +0200,
> Joel Hedlund <joel.hedlund@gmail.com> wrote:
>
> > ... According to PEP8 (python programming style guidelines) you should
> > use 'is' when comparing to singletons like None. I take this to also
> > include constants and such ...
>
> This does *not* also mean constants and such:
>
>     Python 2.4.2 (#1, Feb 22 2006, 08:02:53)
>     [GCC 4.0.1 (Apple Computer, Inc. build 5247)] on darwin
>     >>> a = 123456789
>     >>> a == 123456789
>     True
>     >>> a is 123456789
>     False
>     >>>

Not those kind of constants, but this one:

Python 2.4.2 (#2, Nov 20 2005, 17:04:48)
[GCC 4.0.3 20051111 (prerelease) (Debian 4.0.2-4)] on linux2
>>> CONST = 123456789
>>> a = CONST
>>> a == CONST
True
>>> a is CONST
True
>>>

--
Felipe.


 0
felipe.lessa (207)
3/27/2006 2:08:36 PM
Clemens Hepper wrote:
> It's strange: python seem to cache constants from 0 to 99:

That's true. The Python api doc says that Python keeps an array of
integer objects for all integers between -1 and 100. See
http://docs.python.org/api/intObjects.html.
This also seems to be true for integers from -5 to -2 on (ActiveState)
Python 2.4.2.

--
fw


 0
3/27/2006 5:46:03 PM
In article <48q9pfFlc8q0U1@uni-berlin.de>,
"Diez B. Roggisch" <deets@nospam.web.de> wrote:
....
> So - your conclusion is basically right: use is on (complex) objects, not on
> numbers and strings and other built-ins. The exception from the rule is
> None - that should only exist once, so
>
> foo is not None
>
> is considered better style than foo == None.

But even better style is just foo' or not foo'.  Or not,
depending on what you're thinking.

The key point between is' and ==' has already been made -
- use is' to compare identity
- use ==' to compare value

It's that simple, and it's hard to add to this without
potentially layering some confusion on it.  While Python's
implementation makes the use of identity with small numbers
a slightly more complicated issue, there isn't a lot of
practical difference.  To take a common case that has already
been mentioned here, if I define some constant symbolic values
as small integers, as long as I take care that their values
are distinct, I can reasonably use identity and ignore this
technical weakness.  I can assume that no one is going to
supply randomly selected integers in this context.  Meanwhile,
the use of identity clarifies the intent.

Depending, of course, on what the intent may be, which brings
us to None, and a point about values in Python that was brought
to a fairly brilliant light some years back by someone we don't
hear from often here any more, unfortunately.

- use is' to compare identity
- use ==' to compare value
- use neither to test for somethingness'

I'm not going to try to elucidate the theory of something and
nothing in Python, but suffice it to say that there are places
where it may be better to write

if not expr:

than

if expr is None:

or worse yet,

if expr == False:

That's what I think, anyway.

Donn Cave, donn@u.washington.edu

 0
Donn
3/27/2006 6:00:35 PM
"Clemens Hepper" <ethrandil@gmx.net> wrote in message
news:e08qgg$nt$1@news2.open-news-network.org...

> It's strange: python seem to cache constants from 0 to 99:

The Python specification allows but does not require such behind-the-scenes
implementation optimization hacks.  As released, CPython 2.4 caches -5 to
99, I believe.  In 2.5, the upper limit was increased to 256.  The limits
are in a pair of #define statements in the int object source file.  Anyone
who compiles from source can adjust as desired (though the corresponding
test will fail unless also adjusted ;-).

I think the visibility of this implementation detail from Python code is an
example of a leaky abstraction.  For more, see
http://www.joelonsoftware.com/articles/LeakyAbstractions.html

Terry Jan Reedy


 0
tjreedy (5460)
3/27/2006 10:17:38 PM
Terry Reedy wrote:

> The Python specification allows but does not require such behind-the-scenes
> implementation optimization hacks.  As released, CPython 2.4 caches -5 to
> 99, I believe.  In 2.5, the upper limit was increased to 256.  The limits
> are in a pair of #define statements in the int object source file.  Anyone
> who compiles from source can adjust as desired (though the corresponding
> test will fail unless also adjusted ;-).
>
> I think the visibility of this implementation detail from Python code is an
> example of a leaky abstraction.  For more, see
> http://www.joelonsoftware.com/articles/LeakyAbstractions.html

I don't see that as quite the same thing.  That you can fiddle around
with the is operator to investigate how small integers are cached
doesn't really reveal any profound underlying abstraction, except that
maybe all Python entities are true objects and that integers are
immutable, which are things hopefully everyone was already aware of.

If you're trying to test integer equality, you should be using the ==
operator, not the is operator, so what you find out about how things
are caching is really irrelevant.

--
Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
And covenants, without the sword, are but words and of no strength to
secure a man at all. -- Thomas Hobbes, 1588-1679

 0
max78 (1220)
3/27/2006 10:25:23 PM
Terry Reedy:
>The Python specification allows but does not require such behind-the-scenes
>implementation optimization hacks.  As released, CPython 2.4 caches -5 to
>99, I believe.  In 2.5, the upper limit was increased to 256.  The limits
>are in a pair of #define statements in the int object source file.  Anyone
>who compiles from source can adjust as desired (though the corresponding
>test will fail unless also adjusted ;-).
>
>I think the visibility of this implementation detail from Python code is an
>example of a leaky abstraction.  For more, see
>http://www.joelonsoftware.com/articles/LeakyAbstractions.html

Joel has his abstractions wrong. TCP doesn't guarantee reliable delivery,
unlike IP it delivers reliably or it tells you it cannot. SQL perormance
doesn't break abstraction, since performance isn't part of SQL. You _can_
drive as fast when it's raining.

Now, about identity and equality. As you know, identity implies equality,
but equality doesn't imply identity. You seem to assume that when identity
is not implied, it should be undetectable. But why?

Here's A, there's B, they may or may not be identical, they may or may not
be equal.

What are you suggesting?

1. If A and B are of comparable types, and A equals B, we should not be
allowed to evaluate "A is B".

2. If A and B are of comparable types, and A equals B, A should be B.

3. If A and B are of comparable types, and A equals B, A should not be B.

4. If A and B are of comparable types, and A equals B, "A is B" should not
evaluate to a boolean value.

5. When A and B are of comparable types, we should not be allowed to
evaluate "A == B" :-)

--
Ren� Pijlman

 0
3/27/2006 10:59:37 PM
On Mon, 27 Mar 2006 11:08:36 -0300,
Felipe Almeida Lessa <felipe.lessa@gmail.com> wrote:

> Em Seg, 2006-03-27 às 08:23 -0500, Dan Sommers escreveu:
>> On Mon, 27 Mar 2006 14:52:46 +0200,
>> Joel Hedlund <joel.hedlund@gmail.com> wrote:
>>
>> > ... According to PEP8 (python programming style guidelines) you should
>> > use 'is' when comparing to singletons like None. I take this to also
>> > include constants and such ...
>>
>> This does *not* also mean constants and such:
>>
>> Python 2.4.2 (#1, Feb 22 2006, 08:02:53)
>> [GCC 4.0.1 (Apple Computer, Inc. build 5247)] on darwin
>> >>> a = 123456789
>> >>> a == 123456789
>> True
>> >>> a is 123456789
>> False
>> >>>

> Not those kind of constants, but this one:

> Python 2.4.2 (#2, Nov 20 2005, 17:04:48)
> [GCC 4.0.3 20051111 (prerelease) (Debian 4.0.2-4)] on linux2
>>>> CONST = 123456789
>>>> a = CONST
>>>> a == CONST
> True
>>>> a is CONST
> True
>>>>

That's a little misleading, and goes back to the questions of "what is
assignment in Python?" and "What does it mean for an object to be
mutable?"

The line "a = CONST" simply gives CONST a new name.  After that, "a is
CONST" will be True no matter what CONST was.  Under some circumstances,
I can even change CONST, and "a is CONST" will *still* be True.

>>> CONST = range(22)
>>> a = CONST
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
>>> a is CONST
True
>>> CONST[12] = 'foo'
>>> a is CONST
True
>>>

Right off the top of my head, I can't think of a way to make "a = b; a
is b" return False.

Regards,
Dan

--
Dan Sommers
<http://www.tombstonezero.net/dan/>
"I wish people would die in alphabetical order." -- My wife, the genealogist

 0
me4 (19624)
3/28/2006 2:05:54 AM
Em Seg, 2006-03-27 às 21:05 -0500, Dan Sommers escreveu:
> Right off the top of my head, I can't think of a way to make "a = b; a
> is b" return False.

Sorry for being so --quiet. I will try to be more --verbose.

I can think of two types of constants:
1) Those defined in the language, like True, None, 0 and the like.
2) Those defined on your code.

You said type 1 can be used with "is", you're right:
>>> a = 100
>>> a is 100
False

I said type 2 can (maybe "should"?) be used with "is", and AFAICT I'm
right as well:
>>> b = a
>>> b is a
True

That said, you can do thinks like:
>>> import socket
>>> a = socket.AF_UNIX
>>> a is socket.AF_UNIX
True

That kind of constants can be used with "is". But if don't want to be
prone to errors as I do, use "is" only when you really know for sure
that you're dealing with singletons.

HTH,

--
Felipe.


 0
felipe.lessa (207)
3/28/2006 3:12:15 AM
Felipe Almeida Lessa wrote:
> I said [constants defined in your code] can (maybe "should"?) be used with "is", and
> AFAICT I'm right as well:
> >>> b = a
> >>> b is a
> True

You should _never_ use 'is' to check for equivalence of value. Yes, due
to the implementation of CPython the behaviour you quote above does
occur, but it doesn't mean quite what you seem to think it does.

Try this:

>>> UPPERLIMIT = 100
>>> i = 0
>>> while not (i is UPPERLIMIT):
>>>     i+=1
>>>     print i

Comparing a changing variable to a pre-defined constant seems a lot
more general a use case than sequential binding & comparison...and as
this should show, 'is' does _not_ catch these cases.

- alex23


 0
wuwei23 (1194)
3/28/2006 7:02:09 AM
Op 2006-03-27, Donn Cave schreef <donn@u.washington.edu>:
> In article <48q9pfFlc8q0U1@uni-berlin.de>,
>  "Diez B. Roggisch" <deets@nospam.web.de> wrote:
> ...
>> So - your conclusion is basically right: use is on (complex) objects, not on
>> numbers and strings and other built-ins. The exception from the rule is
>> None - that should only exist once, so
>>
>> foo is not None
>>
>> is considered better style than foo == None.
>
> But even better style is just foo' or not foo'.  Or not,
> depending on what you're thinking.

No it is not. When you need None to be treated special,
that doesn't imply you want to treat zero numbers or empty
sequences as special too.

--
Antoon Pardon

 0
apardon (1080)
3/28/2006 7:45:09 AM
Em Seg, 2006-03-27 às 23:02 -0800, alex23 escreveu:
> Felipe Almeida Lessa wrote:
> > I said [constants defined in your code] can (maybe "should"?) be used with "is", and
> > AFAICT I'm right as well:
> > >>> b = a
> > >>> b is a
> > True
>
> You should _never_ use 'is' to check for equivalence of value. Yes, due
> to the implementation of CPython the behaviour you quote above does
> occur, but it doesn't mean quite what you seem to think it does.

/me not checking for value. I'm checking for identity. Suppose "a" is a
constant. I want to check if "b" is the same constant.

> Try this:
>
> >>> UPPERLIMIT = 100
> >>> i = 0
> >>> while not (i is UPPERLIMIT):
> >>>     i+=1
> >>>     print i
>
> Comparing a changing variable to a pre-defined constant seems a lot
> more general a use case than sequential binding & comparison...and as
> this should show, 'is' does _not_ catch these cases.

That's *another* kind of constant. I gave you the example of
socket.AF_UNIX, the kind of constant I'm talking about. Are you going to
sequentially create numbers until you find it? Of couse not.

The problem with Python (and other languages like Jave) is that we don't
have a type like an enum (yet) so we have to define constants in our
code. By doing an "is" instead of a "==" you *can* catch some errors.
For example, a very dummy function (picked MSG_EOR as its value is
greater than 99):

---
from socket import MSG_EOR, MSG_WAITALL

def test(type):
if type is MSG_EOR:
print "This *is* MSG_EOR"
elif type == MSG_EOR:
print "This maybe be MSG_EOR"
else:
print "*Not MSG_EOR"
---

Now testing it:

>>> test(MSG_EOR)
This *is* MSG_EOR

Fine, but:

>>> print MSG_EOR
128
>>> test(128)
This maybe be MSG_EOR

This is a mistake. Here I knew 128 == MSG_EOR, but what if that was a
coincidence of some other function I created? I would *never* catch that
bug as the function that tests for MSG_EOR expects any integer. By
testing with "is" you test for *that* integer, the one defined on your
module and that shouldn't go out of it anyway.

Of course using an enum should make all said here obsolete.

--
Felipe.


 0
felipe.lessa (207)
3/28/2006 8:03:22 AM
> This does *not* also mean constants and such:
<snip>
>     >>> a = 123456789
>     >>> a == 123456789
>     True
>     >>> a is 123456789
>     False
>     >>>

I didn't mean that kind of constant. I meant named constants with defined
meaning, as in the example that I cooked up in my post. More examples: os.R_OK,
or more complex ones like mymodule.DEFAULT_CONNECTION_CLASS.

Sorry for causing unneccessary confusion.

Cheers!
/Joel Hedlund

 0
3/28/2006 9:31:23 AM
>>You should _never_ use 'is' to check for equivalence of value. Yes, due
>>to the implementation of CPython the behaviour you quote above does
>>occur, but it doesn't mean quite what you seem to think it does.
>
>
> /me not checking for value. I'm checking for identity. Suppose "a" is a
> constant. I want to check if "b" is the same constant.

/me too. That's what my example was all about. I was using identity to a known
CONSTANT (in caps as per python naming conventions :-) to sidestep costly value
equality computations.

> By doing an "is" instead of a "==" you *can* catch some errors.
> <snip>
> By
> testing with "is" you test for *that* integer, the one defined on your
> module and that shouldn't go out of it anyway.

I totally agree with you on this point. Anything that helps guarding against
"stealthed" errors is a good thing by my standards.

Cheers!
/Joel Hedlund

 0
3/28/2006 9:35:31 AM
>>Not those kind of constants, but this one:
>
>
>>Python 2.4.2 (#2, Nov 20 2005, 17:04:48)
>>[GCC 4.0.3 20051111 (prerelease) (Debian 4.0.2-4)] on linux2
>>
>>>>>CONST = 123456789
>>>>>a = CONST
>>>>>a == CONST
>>
>>True
>>
>>>>>a is CONST
>>
>>True
>>
>
> That's a little misleading, and goes back to the questions of "what is
> assignment in Python?" and "What does it mean for an object to be
> mutable?"
>
> The line "a = CONST" simply gives CONST a new name.  After that, "a is
> CONST" will be True no matter what CONST was.  Under some circumstances,
> I can even change CONST, and "a is CONST" will *still* be True.

Anyone who thinks it's a good idea to change a CONST that's not in a module
that they have full control over must really know what they're doing or suffer
the consequences. Most often, the consequences will be nasty bugs.

Cheers!
/Joel Hedlund

 0
3/28/2006 9:40:34 AM
> a is None
>
> is quicker than
>
> a == None

I think it's not such a good idea to focus on speed gains here, since they
really are marginal (max 2 seconds total after 10000000 comparisons):

>>> import timeit
>>> print timeit.Timer("a == None", "a = 1").timeit(int(1e7))
4.19580316544
>>> print timeit.Timer("a == None", "a = None").timeit(int(1e7))
3.20231699944
>>> print timeit.Timer("a is None", "a = 1").timeit(int(1e7))
2.37486410141
>>> print timeit.Timer("a is None", "a = None").timeit(int(1e7))
2.48372101784

Your observation is certainly correct, but I think it's better applied to more
complex comparisons (say for example comparisons between gigantic objects or
objects where value equality determination require a lot of nontrivial
computations). That's where any real speed gains can be found. PEP8 tells me
it's better style to write "a is None" and that's good enough for me. Otherwise
I try to stay away from speed microoptimisations as much as possible since it
generally results in less readable code, which in turn often results in an
overall speed loss because code maintenance will be harder.

Cheers!
/Joel Hedlund

 0
3/28/2006 10:12:52 AM
Am I correct in thinking that there is no longer any link from anywhere
on the Python Web site at http;//www.python.org to the Daily Python-URL
at http://www.pythonware.com/daily/ ? There is no sign of it on the
Community page, nor any reference to it at http://planet.python.org/

I'm sure there was a link to it last time I looked.

Tim C


 0
tchur (177)
3/28/2006 10:38:53 AM
Tim Churches wrote:

> Am I correct in thinking that there is no longer any link from anywhere
> on the Python Web site at http;//www.python.org to the Daily Python-URL
> at http://www.pythonware.com/daily/ ? There is no sign of it on the
> Community page, nor any reference to it at http://planet.python.org/

All links provided on that page would benefit from a short description.

Peter

 0
__peter__ (4031)
3/28/2006 11:06:06 AM
Joel Hedlund wrote:
>>This does *not* also mean constants and such:
>
> <snip>
>
>>    >>> a = 123456789
>>    >>> a == 123456789
>>    True
>>    >>> a is 123456789
>>    False
>
> I didn't mean that kind of constant. I meant named constants with defined
> meaning, as in the example that I cooked up in my post. More examples: os.R_OK,
> or more complex ones like mymodule.DEFAULT_CONNECTION_CLASS.

If it weren't for the current CPython optimization (caching small
integers) this code which it appears you would support writing, would fail:

if (flags & os.R_OK) is os.R_OK:
# do something

while this, on the other hand, is not buggy, because it correctly uses
equality comparison when identity comparison is not called for:

if (flags & os.R_OK) == os.R_OK:
# do something

(I think you should give it up... you're trying to push a rope.)

-Peter


 0
peter34 (3696)
3/28/2006 2:00:38 PM
On Tue, 28 Mar 2006 12:12:52 +0200, Joel Hedlund wrote:

> I try to stay away from speed microoptimisations as much as possible since it
> generally results in less readable code, which in turn often results in an
> overall speed loss because code maintenance will be harder.

+1 QOTW

--
Steven.


 0
steve24 (1018)
3/28/2006 10:35:07 PM
Felipe Almeida Lessa wrote:
> That said, you can do thinks like:
> >>> import socket
> >>> a = socket.AF_UNIX
> >>> a is socket.AF_UNIX
> True
>
> That kind of constants can be used with "is". But if don't want to be
> prone to errors as I do, use "is" only when you really know for sure
> that you're dealing with singletons.

It's only safe to to compare address family values with socket.AF_UNIX
using "is", if small integers are guaranteed to be singletons, and
socket.AF_UNIX has one of those small values.  Otherwise, address
family values equal in value to socket.AF_UNIX can be generated using
different objects.  There's no requirement that the socket module or
anything else return values using the same object that the
socket.AF_UNIX constant uses.

Consider this example using the socket.IPPROTO_RAW constant:

>>> socket.getaddrinfo("localhost", None, socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)[0][2] is socket.IPPROTO_RAW
False

>>> socket.getaddrinfo("localhost", None, socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)[0][2] == socket.IPPROTO_RAW
True

Ross Ridge


 0
rridge (559)
3/28/2006 11:18:10 PM
Em Ter, 2006-03-28 às 15:18 -0800, Ross Ridge escreveu:
[snip]
> Consider this example using the socket.IPPROTO_RAW constant:
>
> >>> socket.getaddrinfo("localhost", None, socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)[0][2] is socket.IPPROTO_RAW
> False
>
> >>> socket.getaddrinfo("localhost", None, socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)[0][2] == socket.IPPROTO_RAW
> True

Ok, you win. It's not safe to do "is" checks on these kinds of
constants.

--
Felipe.


 0
felipe.lessa (207)
3/28/2006 11:44:36 PM
> If it weren't for the current CPython optimization (caching small
> integers)

> this code which it appears you would support writing
>
>    if (flags & os.R_OK) is os.R_OK:

I do not.

You compare a module.CONSTANT to the result of an expression (flags & os.R_OK).
Expressions are not names bound to objects, the identity of which is what I'm
talking about. This example does not apply. Also, the identity check in my
example has a value equality fallback. Yours doesn't, so it really does not apply.

> (I think you should give it up... you're trying to push a rope.)

I'm not pushing anything. I just don't like being misquoted.

Cheers,
Joel Hedlund

 0
3/29/2006 7:44:44 AM
> There's no requirement that the socket module or
> anything else return values using the same object that the
> socket.AF_UNIX constant uses.

Ouch. That's certainly an eyeopener.

For me, this means several things, and I'd really like to hear people's

It basically boils down to "don't ever use 'is' unless pushed into a corner,
and nevermind what PEP8 says about it".

So here we go... *takes deep breath*

Identity checks can only be done safely to compare a variable to a defined
builtin singleton such as None. Since this is only marginally faster than a
value equality comparison, there is little practical reason for doing so.
(Except for the sake of following PEP8, more of that below).

You cannot expect to ever have identity between a value returned by a
function/method and a CONSTANT defined in the same package/module, if you do
not have comlete control over that module. Therefore, such identity checks
should always be given a value equality fallback. In most cases the identity
check will not be significantly faster than a value equality check, so for the
sake of readability it's generally a good idea to skip the identity check and
just do a value equality check directly. (Personally, I don't think it's good
style to define constants and not be strict about how you use them, but that's
on a side note and not very relevant to this discussion)

It may be a good idea to use identity checks for variables vs CONSTANTs defined
in the same module/package, if it's Your module/package and you have complete
control over it. Felipe Almeida Lessa provided a good argument for this earlier

> Here I knew 128 == MSG_EOR, but what if that was a
> coincidence of some other function I created? I would *never* catch that
> bug as the function that tests for MSG_EOR expects any integer. By
> testing with "is" you test for *that* integer, the one defined on your
> module and that shouldn't go out of it anyway.

However it may be a bad idea to do so, since it may lure you into a false sense
of security, so you may start to unintentionally misuse 'is' in an unsafe manner.

So the only motivated use of 'is' would then be the one shown in my first
example with the massive_computations() function: as a shortcut past costly
value equality computations where the result is known, and with an added value
equality fallback for safety. Preferably, the use of identity should then also
be motivated in a nearby comment.

code. You should never use it, unless it leads to a *measurable* gain in
performance, in which it should also be given a value equality fallback and a
comment. And lastly, PEP8 should be changed to reflect this.

Wow... that got a bit long and I applaud you for getting this far! :-) Thanks
for taking the time to read it.

Cheers!
/Joel Hedlund

 0
3/29/2006 9:08:38 AM
Joel Hedlund wrote:

> For me, this means several things, and I'd really like to hear people's
>
> It basically boils down to "don't ever use 'is' unless pushed into a corner,
> and nevermind what PEP8 says about it".

nonsense.

> Identity checks can only be done safely to compare a variable to a defined
> builtin singleton such as None.

utter nonsense.

> You cannot expect to ever have identity between a value returned by a
> function/method and a CONSTANT defined in the same package/module, if you do
> not have comlete control over that module.

or if the documentation guarantees that you can use "is" (e.g. by specifying
that you get back the object you passed in, or by specifying that a certain
object is a singleton, etc).

> Therefore, such identity checks should always be given a value equality
> fallback.

if the documentation guarantees that you can use "is", you don't need any
"value equality fallback".

> My conlusion is then that using 'is' is a bad habit and leads to less readable
> code. You should never use it, unless it leads to a *measurable* gain in
> performance, in which it should also be given a value equality fallback and a
> comment. And lastly, PEP8 should be changed to reflect this.
>
> Wow... that got a bit long and I applaud you for getting this far! :-) Thanks
> for taking the time to read it.
>

you need to spend more time relaxing, and less time making up arbitrary
rules for others to follow.

read the PEP and the documentation.  use "is" when you want object identity,
and you're sure it's the right thing to do.  don't use it when you're not sure.
any other approach would be unpythonic.

</F>


 0
fredrik2101 (5275)
3/29/2006 9:41:46 AM
sorry

> You compare a module.CONSTANT to the result of an expression

s/an expression/a binary operation/

/joel

Joel Hedlund wrote:
>>If it weren't for the current CPython optimization (caching small
>>integers)
>
>
>
>
>>this code which it appears you would support writing
>>
>>   if (flags & os.R_OK) is os.R_OK:
>
>
> I do not.
>
> You compare a module.CONSTANT to the result of an expression (flags & os.R_OK).
> Expressions are not names bound to objects, the identity of which is what I'm
> talking about. This example does not apply. Also, the identity check in my
> example has a value equality fallback. Yours doesn't, so it really does not apply.
>
>  > (I think you should give it up... you're trying to push a rope.)
>
> I'm not pushing anything. I just don't like being misquoted.
>
> Cheers,
> Joel Hedlund

 0
3/29/2006 9:42:59 AM
Joel Hedlund wrote:
>> There's no requirement that the socket module or
>> anything else return values using the same object that the
>> socket.AF_UNIX constant uses.
>
>
> Ouch. That's certainly an eyeopener.
>
> For me, this means several things, and I'd really like to hear people's
>
> It basically boils down to "don't ever use 'is' unless pushed into a
> corner, and nevermind what PEP8 says about it".

Identity checks are often used for checking input parameters of a function:

def somefunc(val=None):
if val is None:
val = []
do_stuff(val)

Or if None is a possible parameter you can use your own object as a marker::

_marker = []

def somefunc(val=_marker):
if val is marker:
val = []
do_stuff(val)

--

hilsen/regards Max M, Denmark

http://www.mxm.dk/

Phone:  +45 66 11 84 94
Mobile: +45 29 93 42 96

 0
maxm (304)
3/29/2006 10:01:18 AM
>> For me, this means several things, and I'd really like to hear people's

> you need to spend more time relaxing, and less time making up arbitrary
> rules for others to follow.

I'm very relaxed, thank you. I do not make up rules for others to follow. I ask
for other peoples opinions so that I can reevaluate my views.

I do respect your views, as I clearly can see you have been helpful and
constructive in earlier discussions in this newsgroup. So therefore if you
think my statements are nonsense, there's a good chance you're right. And
that's why I posted. To hear what other people think.

Sorry if I came off stiff and belligerent because that certainly wasn't ny intent.

> read the PEP and the documentation.

Always do.

> use "is" when you want object identity,
> and you're sure it's the right thing to do.  don't use it when you're not sure.
> any other approach would be unpythonic.

Right.

Chill!
/Joel Hedlund

>
> </F>
>
>
>

 0
3/29/2006 10:52:27 AM
Joel Hedlund wrote:

> It basically boils down to "don't ever use 'is' unless pushed into a
> corner, and nevermind what PEP8 says about it".

A quick grep[*] of the Python library shows the following common use-cases
for 'is'. The library isn't usually a good indicator of current style
though: a lot of it was forced to do things differently at the time when it
was written. (Also, my search includes site-packages so this isn't all
standard lib: I found 5091 uses of the keyword 'is').

Comparison against None '<expr> is None' or '<expr> is not None' are by far
the commonest.

Comparison against specific types or classes are the next most common (in
the standard library '<expr> is type([])' although if the code were
rewritten today and didn't need backward compatability it could just do
'<expr> is list'.

Comparison against sentinal or marker objects e.g. in the standard library
this is usually a constant set to [].

Other singletons e.g. NotImplemented

code.py has:
if filename and type is SyntaxError:
which might be better style if it used 'issubclass' rather than 'is'.

if port is None and port_specified is True:
naughty.

difflib.py uses:
if a is self.a:
return
in SequenceMatcher to avoid recomputing related values when changing one or
other of the sequences.

doctest does some fairly advanced identity testing. It also has:

SUCCESS, FAILURE, BOOM = range(3) # outcome state
...
if outcome is SUCCESS:
...
elif outcome is FAILURE:
...
elif outcome is BOOM:

fnmatch.py uses 'is' on some module names to optimise out a function call.

optparse.py uses 'is' to test for non-default options, but it has some
pretty dubious ways of generating the values it tests against:
NO_DEFAULT = ("NO", "DEFAULT")
SUPPRESS_HELP = "SUPPRESS"+"HELP"
SUPPRESS_USAGE = "SUPPRESS"+"USAGE"
....
if default_value is NO_DEFAULT or default_value is None:
default_value = self.NO_DEFAULT_VALUE
....
if not option.help is SUPPRESS_HELP:
....
elif usage is SUPPRESS_USAGE:

sre defines a bunch of constants strings like an enumeration and uses 'is'
to test them.

if self.__owner is me:

Non standard library:

Spambayes has:
if val is True:
val = "Yes"
elif val is False:
val = "No"
when displaying configuration options to the user.

zsi does things like:
if item.isSimple() is True:
if item.content.isRestriction() is True:
self.content = RestrictionContainer()
elif item.content.isUnion() is True:
self.content = UnionContainer()
elif item.content.isList() is True:
self.content = ListContainer()
ick.

[*] I discovered a neat feature I didn't know my editor had: grepping for
"<[c:python-keyword>is" finds all occurences of the keyword 'is' while
ignoring it everywhere it isn't a keyword.

 0
duncan.booth (1734)
3/29/2006 12:18:17 PM
> [*] I discovered a neat feature I didn't know my editor had: grepping for
> "<[c:python-keyword>is"

Neat indeed. Which editor is that?

Thanks for a quick and comprehensive answer, btw.

Cheers!
/Joel

 0
3/29/2006 12:44:57 PM
Joel Hedlund wrote:

>> [*] I discovered a neat feature I didn't know my editor had: grepping
>> for "<[c:python-keyword>is"
>
> Neat indeed. Which editor is that?

Epsilon from www.lugaru.com. The drawback is that it costs real money
although you can try the beta for the next version until it is released.

 0
duncan.booth (1734)
3/29/2006 1:12:44 PM
On Mon, 2006-03-27 at 17:17 -0500, Terry Reedy wrote:
> "Clemens Hepper" <ethrandil@gmx.net> wrote in message
> news:e08qgg$nt$1@news2.open-news-network.org...
>
> > It's strange: python seem to cache constants from 0 to 99:
>
> The Python specification allows but does not require such behind-the-scenes
> implementation optimization hacks.  As released, CPython 2.4 caches -5 to
> 99, I believe.  In 2.5, the upper limit was increased to 256.  The limits
> are in a pair of #define statements in the int object source file.  Anyone
> who compiles from source can adjust as desired (though the corresponding
> test will fail unless also adjusted ;-).
>
> I think the visibility of this implementation detail from Python code is an
> example of a leaky abstraction.  For more, see
> http://www.joelonsoftware.com/articles/LeakyAbstractions.html

I disagree wholeheartedly with this.  == and is are two very different
operators that have very different meaning.  It just happens that the
logical operation

(a is b ) -> (a == b )

is always True.

There is no abstraction going on here; a==b is not an abstract version
of a is b.  They are different operations.

a == b tests if the values of objects at a and b are equal.  a and b
point be the same darn object, or they might be different objects, but
the question we are asking is if they have the same value.

The is operator is different, you use it if you are interested in
introspecting the language.

Some people have noticed that  1 + 1 is 2 will return True and  1 + 100
is 101 returns False.   This isn't a "leaky abstraction" unless you
wrongly consider is to be an analogy for ==.

Python has certain optimizations ... small strings and numbers are
"interned," that is canonical copies are maintained and efforts to
create fresh objects result in the old cached copies being returned,
albeit with higher reference counts.  This saves memory and time; time
because for any intern-able objects the truth of the first test is a
realistic possibility.

if a is b:
return True
if hash( a ) != hash( b )
return False
.... Now do proper equality testing. ...

As for "joelonsoftware's" leaky abstraction article, I respectfully
disagree.  His leaky abstractions are merely inappropriate analogies.
TCP is perfectly reliable with respect to its definition of
reliability.

As for wipers abstracting away the rain ...

Well over a decade ago I recall walking to lunch with my supervisor, a
truly masterful C programmer.  We worked in Manhattan, a land where two
way streets are the exception.  When crossing each street he would look
the wrong way, look the correct way and then stare the wrong way again.
Upon noticing my inquisitorial expression, he answered "A good
programmer always looks both ways when crossing a one way street."

I'm uncertain that a quip about abstracting away the rain would have
prompted the same adjective "masterful" now 10+ years in the future.


 0
4/3/2006 2:11:44 PM
Adam DePrince  <adam.deprince@gmail.com> wrote:
> It just happens that the
>logical operation
>
> (a is b ) -> (a == b )
>
>is always True.

Only for small values of "always".  You can always do pathological
things with operators:

class Foo:
def __eq__ (self, other):
return False

f = Foo()
print f is f
print f == f

frame:play$./is.py True False This may even be useful. What if you were trying to emulate SQL's NULL? NULL compares false to anything, even itself. To test for NULLness, you have to use the special "is NULL" operator.   0 roy (2295) 4/3/2006 2:37:11 PM On 3 Apr 2006 10:37:11 -0400 in comp.lang.python, roy@panix.com (Roy Smith) wrote: >Adam DePrince <adam.deprince@gmail.com> wrote: >> It just happens that the >>logical operation >> >> (a is b ) -> (a == b ) >> >>is always True. > >Only for small values of "always". You can always do pathological >things with operators: > >class Foo: > def __eq__ (self, other): > return False > >f = Foo() >print f is f >print f == f > >frame:play$ ./is.py
>True
>False
>
>This may even be useful.  What if you were trying to emulate SQL's
>NULL?  NULL compares false to anything, even itself.  To test for
>NULLness, you have to use the special "is NULL" operator.

Another instance where this may be useful is IEEE-754 NaN.  I don't
have fpconst to verify if that's the case, but I would expect
NaN is NaN to be true, but NaN == NaN to be false.

Regards,
-=Dave

--
Change is inevitable, progress is not.

 0
iddw (680)
4/3/2006 2:48:09 PM
In article <e0rbun$70g$1@panix2.panix.com>, Roy Smith wrote:
> This may even be useful.  What if you were trying to emulate SQL's
> NULL?  NULL compares false to anything, even itself.

Strictly speaking, comparing NULL to anything gives NULL, not False.

 0
usenet (110)
4/3/2006 2:58:13 PM
Adam DePrince wrote:

> It just happens that the
> logical operation
>
>  (a is b ) -> (a == b )
>
> is always True.

That is incorrect:

>>> inf = 1e300*1e300
>>> nan = inf-inf
>>> nan is nan, nan==nan
(True, False)
`
 0
duncan.booth (1734)
4/3/2006 3:00:38 PM

Similar Artilces:

'is not' or '!='
A newbie question to you; what is the difference between statements like: if x is not None: and if x != None: Without any context, which one should be preferred? IMHO, the latter is more readable. On 2014-08-18 21:35, ElChino wrote: > A newbie question to you; what is the difference between statements > like: > if x is not None: > and > if x != None: > > Without any context, which one should be preferred? > IMHO, the latter is more readable. > "x == y" tells you whether x and y refer to objects that are equal. "x is y&qu...

'^=' and '~='?
Hello, What is the difference between '^=' and '~='? Thanks, Duckhye ...

difference between ',' and 'a,'
Small question. In gforth is there a difference between the words ',' and 'a,'? I'm thinking not, so perhaps another question, why have both ',' and 'a,'? Thanks Should be the same, in gforth: see , : , here cell allot ! ; ok see a, : , here cell allot ! ; ok On Friday, January 9, 2015 at 5:46:04 AM UTC-8, beeflo wrote: > Small question. In gforth is there a difference between the words ',' and 'a,'? > > I'm thinking not, so perhaps another question, why have both ',' and 'a,'...

'''''''''''''The Running Update/Append Queries Using VBA code Ordeal''''''''''''''
Hello fellow programmers, I am trying to run an append/update query from code, a command button on a form initiates the queries. the format i am using is; _____________________________________________________ SELECT "criteria" FROM "criteria" WHERE "criteria" UPDATE/APPEND "field selections" RecordSource "qryExample" = above text strings" _______________________________________________________________________ When i am running a SELECT query in this manner it works fine with no problems, and accepts the values of specified linked for...

'''''''''''''The Running Update/Append Queries Using VBA code Ordeal'''''''''''''' #2
Hi, Thanks for ur help there HJ. I know how to do the tasks you specified there. I would like for the update query to use field values from some of the fields on the form (frmInvoices) such as InvoiceNumber, DateFrom, DateTo. My problem is that an append/update query can't find the values in the open Form (frmInvoices) when I specify them as; [Forms]![frmInvoices]![InvoiceNumber] a select query has no problem finding the field values on a form. please help. Aaron Hi Aaron, Could you post the entire code that you are having trouble with? Now it is not possible to see what goes wron...

if str_mo not in ('','.') and str_da not in ('','.') and str_yy not in ('','.') Any shorter ?
Hi, there. =20 I'm just curious if it ever dawned on anybody how to abbreviate this line : if str_mo not in ('','.') and str_da not in ('','.') and str_yy not in ('','.')=20 =20 Igor Kurbeko Clinical Programmer Analyst 678 336 4328 ikurbeko@atherogenics.com =20 no brain no pain =20 how about: if not (str_mo in ('','.') or str_da in ('','.') or str_yy in ('','.')) OR if not (missing(str_mo) or missing(str_da) or missing(str_yy)) Eric On 22 Oct 03 21:13:37 GMT, ikurbeko@ATHER...

A function with 'and' , 'not' , 'null' , 'car' and 'cdr'
What's this ? (defun enigma (x) (and (not (null x)) (or (null (car x)) (enigma (cdr x))))) "I suppose I should learn Lisp, but it seems so foreign." - Paul Graham, Nov 1983 On Wed, Oct 07 2015, CAI GENGYANG wrote: > What's this ? > > > (defun enigma (x) > (and (not (null x)) > (or (null (car x)) > (enigma (cdr x))))) Bad taste? It returns T if the list X contains nil as an element. It would be clearer to write (some #'null x). Helmut CAI GENGYANG ...

Difference between '@' and 'inline'
I have a doubt about the use of '@' and 'inline' I calculated an integral to show my doubt The integral is: (2*x*y + y^2)dydx variation in y: 0 to 2 variation in x: 1 to 3 % Calculating of a integral f = @(y,x) 2.*x.*y + y.^2; format rat; Result1 = dblquad(f,0,2,1,3) % Another way clear all syms x y f = inline(vectorize(2*x*y + y^2),'y','x'); format rat Result2 = dblquad(f,0,2,1,3) The answers are the same. I'd like to know what's the diferrence between '@'(used in the first calculation) and 'inline'(used in the second calculation)....

which is more 'pythonic' / 'better' ?
hi, there are 2 versions of a simple code. which is preferred? === if len(line) >= (n+1): text = line[n] else: text = 'nothing' === === try: text = line[n] except IndexError: text = 'nothing' === which is the one you would use? thanks, gabor gabor wrote: > hi, > > there are 2 versions of a simple code. > which is preferred? > > > === > if len(line) >= (n+1): > text = line[n] > else: > text = 'nothing' > === > > > === > try: > text = line[n] > except IndexError: > text = '...

Re: if str_mo not in ('','.') and str_da not in ('','.') and str_yy not in ('','.') Any shorter ?
OR you could use ARRAY data new; set old; array igor $(*) str_mo str_da str_yr; do over igor; if igor ~in (' ','.') then do; end; run; Prasad Ravi Igor Kurbeko <ikurbeko@ATHEROGENIC To: SAS-L@LISTSERV.UGA.EDU S.COM> cc: Sent by: "SAS(r) Subject: if str_mo not in ('','.') and str_da not in ('','.') and str_yy ... error: expected '=', ',', ';', 'asm' or '__attrib Hi I'm trying to compile an ADC Driver & come acrosss the following error. I've no experience writing drivers before, and hence have no clue how to fix it. Hope someone out there has encountered the problem & suggesst a fix for the same. The Error is I get is : qadc.c: At top level: qadc.c:97: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'qadc_read' make: *** [qadc.o] Error 1 [root@localhost qadc]# ########################################################################### ADC Driver Code ####################... error: expected '=', ',', ';', 'asm' or '__attrib Hi I'm trying to compile an ADC Driver & come acrosss the following error. I've no experience writing drivers before, and hence have no clue how to fix it. Hope someone out there has encountered the problem & suggesst a fix for the same. The Error is I get is : qadc.c: At top level: qadc.c:97: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'qadc_read' make: *** [qadc.o] Error 1 [root@localhost qadc]# ########################################################################### ADC Driver Code ##... Does '!=' equivelent to 'is not' I'm a bit confusing about whether "is not" equivelent to "!=" if a != b: ... if a is not b: ... What's the difference between "is not" and "!=" or they are the same thing? pirata wrote: > I'm a bit confusing about whether "is not" equivelent to "!=" > > if a != b: > ... > > if a is not b: > ... > > > What's the difference between "is not" and "!=" or they are the same thing? No, they are not the same thing. == and != test to see if the *value* of two ... replacing '/' with '\\' I have a MKS ksh shell script running on a Windows box. In some scripts I have to convert a UNIX filename into a DOS filename, that is replace the '/' with '\\'. For example, replace /opt/siips/archive/text.dat with \\opt\\siips\\archive\\text.dat. I've tried using sed like$FILE='echo \$FILE|sed "s/\//\\\/g"' which got me \opt\siips\archive\text.dat. It's close but I still need the second \. Does anyone have any suggestion? Or tell me where I've gone wrong? Thanks -- Steffen On 9 Dec 2004 20:14:21 -0800, sajohn52@yahoo.com <sajohn52@yahoo....

Web resources about - Difference between 'is' and '==' - comp.lang.python

Resources last updated: 2/3/2016 1:43:08 AM