Reference

A

ast

hello

Consider following code:
True

I understand that there is a single object 7 somewhere in memory and
both variables A and B point toward this object 7

now do the same with a list:
l1 = [1, 2]
l2 = [1, 2]
l1 is l2
False

It seems this time that there are 2 distincts objects [1, 2] in memory. l1 points
toward the first one and l2 points toward the second one.

if I change one, the second remains unchanged
[1, 2]

I dont really understand why the behavior is different.
Both integer 7 and list [1, 2] are objects. Why is it
different ?

thanks
 
M

Mark H. Harris

Consider following code:

True

The names A and B are both bound to the same object (7).
You will discover that this is True for all small ints less
than 257; on CPython3.3.4. I just checked it. :)

Its just more efficient to do this for small ints because they
are immutable (1) and because they are used for frequently (2).

As somebody pointed out last week, don't use "is" for ints and
strings (generally speaking). Value is what's important here,
not identity. My python coding is yet simple and straight
forward enough that I have not had a need yet for "is".

Cheers
marcus
 
G

Grant Edwards

hello

Consider following code:

True

I understand that there is a single object 7 somewhere in memory

Maybe, maybe not. Integer are immutable, so that's allowed but not
required. In CPython, that's true for small integers, but that is an
implementation detail, and you shouldn't depend on it.
and both variables A and B point toward this object 7

They might. They might not.
now do the same with a list:
l1 = [1, 2]
l2 = [1, 2]
l1 is l2
False

It seems this time that there are 2 distincts objects [1, 2] in
memory.

Yep. Lists are mutable, therefore each literal produces a distinct
object.
l1 points toward the first one and l2 points toward the
second one.
Yep.

I dont really understand why the behavior is different.
Both integer 7 and list [1, 2] are objects. Why is it
different ?

Integer objects are immutable (they can't change value), therefore you
can reuse them without causing problems. Lists are mutable (you can
change the values in them), so you can't reuse them.
 
R

Rustom Mody

Consider following code:

I understand that there is a single object 7 somewhere in memory and
both variables A and B point toward this object 7
now do the same with a list:
l1 = [1, 2]
l2 = [1, 2]
l1 is l2
False

It seems this time that there are 2 distincts objects [1, 2] in memory. l1 points
toward the first one and l2 points toward the second one.
if I change one, the second remains unchanged
l1.append(3)
l1 [1, 2, 3]
l2
[1, 2]
I dont really understand why the behavior is different.
Both integer 7 and list [1, 2] are objects. Why is it
different ?

Short answer: Avoid using 'is'.

Long answer: http://www.beyondwilber.ca/healing-thinking/non-identity-korzybski.html

Pragmatic answer: Think of 'is' as a short-form for 'machine-rep-is'
And use machine representations with the same alacrity that a
C programmer uses inline assembly
 
T

Terry Reedy

Consider following code:

The 'is' operator has three uses, two intended and one not. In
production code, 'is' tests that an object *is* a particular singular
object, such as None or a sentinel instance of class object. In test
code, 'is' can also be used to test details of a particular
implementation, such as pre-allocation of small ints. New python
programmers also use it to confuse themselves.
 
T

Tim Chase

Interesting, but mostly a distraction for the querent here.

Short answer: Use ‘use’ any time you need to compare object
identity. You usually do not need to compare object identity.

I think there use something wrong with that sentence...unless there
usen't. ;-)

-tkc
 
M

Mark Lawrence

This is bad advice in a Python forum.

The ‘is’ operator is commonly used in Python, so please don't advise
against it in an unqualified “short answerâ€.


Interesting, but mostly a distraction for the querent here.

Short answer: Use ‘use’ any time you need to compare object identity.
You usually do not need to compare object identity.

That last paragraph is as clear as mud.

I'd just like to know why people are so obsessed with identities, I've
never thought to use them in 10+ years of writing Python. Do I use the
KISS principle too often?
 
T

Tim Chase

I'd just like to know why people are so obsessed with identities,
I've never thought to use them in 10+ years of writing Python. Do
I use the KISS principle too often?

There are a couple use-cases I've encountered where "is" matters:

1) the most popular:

if foo is None:
do_stuff()

2) sentinels (which are effectively non-None None values)

SENTINEL = object()

def myfuntion(value=SENTINEL):
if value is SENTINEL:
do_something_parameterless()
else:
do_something_else(value) # allow for value=None

3) when doing recursion and you want to prevent touching the same
object multiple times, such as what happens when you do

lst = [1,2,3]
lst.append(lst)
print(lst)

and it needs to recognize that the final element of "lst" is one that
it has already seen (as done by identity).


There might be some other use cases, but #1 is a good 95% of my
usage, #2 is a good 4%, and I can only think of once in my Python
career when I've needed to do what is described in #3.

-tkc
 
J

Jerry Hill

There are a couple use-cases I've encountered where "is" matters:

1) the most popular:

if foo is None:
do_stuff()

I know this is the one that always comes up, but honestly, I feel like
"is" doesn't matter here. That code would be just as correct if it
was written as:

if foo == None:
do_stuff()

The only time it would give you a different result from the "is"
version is if foo was bound to an object that returned True when
compared with None. And if that were the case, I'm still not
convinced that you can tell from looking at those two lines of code
which one is buggy, except for the fact that there has been 20 years
of custom saying that comparing to None with equality is wrong.
 
M

Marko Rauhamaa

Mark Lawrence said:
I'd just like to know why people are so obsessed with identities, I've
never thought to use them in 10+ years of writing Python. Do I use the
KISS principle too often?

Calmly choosing the right tool for the job is not an obsession.


Marko
 
M

Marko Rauhamaa

Jerry Hill said:
except for the fact that there has been 20 years of custom saying that
comparing to None with equality is wrong.

"if foo == None" is not wrong in any manner. It's just that if you are
comfortable with the "is" operator and its semantics, "if foo is None"
is slightly more natural.

You generally use "==" if more than one object could be equal. If you
know there's only one object of the kind, you convey that knowledge by
the use of "is" even when functionally, it doesn't matter.


Marko
 
C

Chris Angelico

You generally use "==" if more than one object could be equal. If you
know there's only one object of the kind, you convey that knowledge by
the use of "is" even when functionally, it doesn't matter.

It's even simpler than that.

You use "==" when you care about value, and "is" when you care about identity.

This is because "==" tests value, and "is" tests identity.

I do not understand why there is confusion.

ChrisA
 
R

Roy Smith

Ben Finney said:
That's right. Python provides this singleton and then recommends you
compare with ‘is’, precisely to protect against pathological cases like
a “return True when compared for equality with None†data type.

Going off on a tangent, I've often wished Python provided more kinds of
None-ness. I'll often write:

def f(arg=None):
whatever

where it would be nice to differentiate between "this was called with no
arguments" and "this was called with an argument of None". Sure, I can
work around that with things like **kwargs, and then test

"args" in kwargs

vs.

kwargs["args"] is None

but that always feels clumsy. It also makes the function declaration
less sell-describing. "Hmmm, let's see what help() says. Oh, gee, I
can pass it some stuff".
 
C

Chris Angelico

Going off on a tangent, I've often wished Python provided more kinds of
None-ness. I'll often write:

def f(arg=None):
whatever

where it would be nice to differentiate between "this was called with no
arguments" and "this was called with an argument of None".

That's why you have your own sentinel.

_NONE_PASSED=object()
def f(arg=_NONE_PASSED):
if f is not _NONE_PASSED: pass

ChrisA
 
S

Steven D'Aprano

The 'is' operator has three uses, two intended and one not. In
production code, 'is' tests that an object *is* a particular singular
object, such as None or a sentinel instance of class object. In test
code, 'is' can also be used to test details of a particular
implementation, such as pre-allocation of small ints. New python
programmers also use it to confuse themselves.


+1 QOTW
 
S

Steven D'Aprano

I know this is the one that always comes up, but honestly, I feel like
"is" doesn't matter here. That code would be just as correct if it was
written as:

if foo == None:
do_stuff()

The only time it would give you a different result from the "is" version
is if foo was bound to an object that returned True when compared with
None. And if that were the case, I'm still not convinced that you can
tell from looking at those two lines of code which one is buggy,


It's all about the intention of the code.

Are you trying to test whether an object *is* the None singleton, and no
other value? Then use "is", don't use == because it is subject to false
positives (returning True for some objects that aren't actually None).

Or do you want to test whether an object merely happens to have the same
value as None? Then use == and be glad.

Personally, I have never written code that looks like this:

def spam(a, b=None):
"""Spamify a with optional b.

If b is None ***OR SOMETHING THAT COMPARES EQUAL TO NONE***
or not supplied, use extra-yummy spammification mode.
"""
if b == None: ...


But if I ever did want to do that, I can.

Since None is a singleton null-object, something with no state and no
behaviour, we normally treat it as a sentinel, in which case an identity
test is usual. I can't really think of any good reason to treat it as a
value where I would want to use an equality test.

except
for the fact that there has been 20 years of custom saying that
comparing to None with equality is wrong.

It's not *necessarily* wrong, merely wrong the 99.9998% of the time that
you want to treat None as a sentinel.
 
S

Steven D'Aprano

Going off on a tangent, I've often wished Python provided more kinds of
None-ness. I'll often write:

def f(arg=None):
whatever

where it would be nice to differentiate between "this was called with no
arguments" and "this was called with an argument of None". Sure, I can
work around that with things like **kwargs,


That's the hard way. The easy way is:

_SENTINEL = object()

def f(arg=_SENTINEL):
if arg is _SENTINEL:
...


If you really cared, you could implement your own None_ish_Type and
create as many named sentinels as you wish.
 
S

Steven D'Aprano

"if foo == None" is not wrong in any manner. It's just that if you are
comfortable with the "is" operator and its semantics, "if foo is None"
is slightly more natural.

You generally use "==" if more than one object could be equal. If you
know there's only one object of the kind, you convey that knowledge by
the use of "is" even when functionally, it doesn't matter.

I don't agree that it doesn't matter. Code, even when functionally
equivalent, should express the intention of the programmer in as simple a
fashion as is possible given the constraints of the task, performance,
etc. For example, if you want to add 1 to a number, you would write:

x += 1


not:

x += (127 - 102)//(5**2)

even though you know that the two expressions are exactly equivalent.
Even if you know that there is a peep-hole optimizer that ensures that
the code actually compiled is "x += 1". The intention to the reader is
important.

This is why, unless performance is *really* critical, one should normally
write x*2 when multiplying x by 2 rather than x >> 1. (And in Python, the
overhead means that there is no real performance benefit to using bit
shifts instead of multiplication or division.)

If your intention is to treat None as a singleton sentinel, not as a
value, then you ought to use "is" to signal that intention, rather than
using == even if you know that there won't be any false positives.
 
C

Chris Angelico

This is why, unless performance is *really* critical, one should normally
write x*2 when multiplying x by 2 rather than x >> 1. (And in Python, the
overhead means that there is no real performance benefit to using bit
shifts instead of multiplication or division.)

In most C compilers today (C being where x << 1 would be used rather
than x * 2), the expressions would be equivalent, so you can still
express it as x * 2 and let the compiler turn that into a bit shift.
(And it's possible that "x * 5" will become "x << 2 + x", too.)
Definitely go for the expressive version unless you've actually tested
that the obscure version is faster.

(Of course, that doesn't mean the bit-shift operators should never be
used. If you're trying to pack three tiny integers into a single
larger integer, you probably want bit shifts and bitwise or, not
multiplication and addition, even though either would work.)

Code should look like its intent. Warping it around performance is
hardly ever worthwhile.

ChrisA
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top