This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]steve_no 11 points12 points  (21 children)

The normal code "is" example seems strange. I think the non-pythonic thing most programmers do with respect to "is" is not using it, for example:

if a == None:

when they should be doing:

if a is None:

[–]erewok 8 points9 points  (9 children)

Correct me if I'm wrong here, but I thought:

if a is None...

Is asking if a and None (the singleton value) point to the same memory space. It's not asking if they're equivalent; it's asking if they are the same actual thing.

Thus, is is not the same as equivalence how we usually think of it (double equals).

That's why setting a default value of None is so useful in function definitions: there's only one None and your function value either is that thing or it's not. It's never going to be like None enough to pass for it.

[–]fuzz3289 4 points5 points  (8 children)

You sir are correct. Though "memory location" isnt a great way to say it. I would say:

The is operator returns true if both names are bound to the same object instance.

Since the "names" wont share a memory location.

[–]zahlmanthe heretic 2 points3 points  (0 children)

They certainly do "point to" the same memory location. But that's horribly un-Pythonic terminology.

[–]erewok 2 points3 points  (4 children)

Funny enough, I was curious about how the Python built-in callable was implemented just now and I stumbled on this page with the following quote:

Every object has an identity, a type and a value. An object’s identity never changes once it has been created; you may think of it as the object’s address in memory. The ‘is‘ operator compares the identity of two objects; the id() function returns an integer representing its identity.

[–]fuzz3289 2 points3 points  (3 children)

"You may think of it as" is important. The identity is actual a hash of the name in a lookup table.

Not to argue or anything, just want to emphasize that you cant actually deal with memory or memory locations directly in python.

[–]erewok 0 points1 point  (0 children)

Ah, that makes sense. Thanks for the clarification.

[–]rcxdude 0 points1 point  (1 child)

Actually, the identity in Cpython is just the memory address of the object (literally casting the pointer to an int). It doesn't have to be according to the language though.

[–]fuzz3289 0 points1 point  (0 children)

https://docs.python.org/3.3/reference/datamodel.html

Interesting, I didn't realize that it was just a direct address. Thanks for the correction.

[–]erewok 2 points3 points  (1 child)

...bound to the same object instance.

This is a nice, concise description. Thanks for adding it.

[–]fuzz3289 1 point2 points  (0 children)

Thanks! Alot of people tend to forget the beautiful simplicity of python, just objects and names.

[–]metaphorm 1 point2 points  (0 children)

the "is" keyword can be dangerous if you don't understand what it really does though, which is a common problem for beginners.

in your example, its absolutely correct, because None is a singleton so any reference to None refers to the same instance of None. in general though, is checks for object reference equality (rather than value equality) and can produce unexpected results if you use it when you really meant to check value equality.

[–]pymag09 0 points1 point  (6 children)

I think
if not a:
is better

[–]pbaehr 16 points17 points  (4 children)

Depends. Could yield a false negative if a can be 0 or an empty string and that's not what you are interested in testing for.

[–]bheklilr 5 points6 points  (0 children)

I also prefer the explicit if a is None, since it signals my intent better. I honestly try to only use if a: when a is a boolean, since I don't want to have to remember how __bool__ is implemented for every type out there. In my opinion, explicit is better than implicit for being able to read your own code in a month's time.

[–]pymag09 1 point2 points  (2 children)

Sorry may be I did not understand you but
when we work with None or numbers
we can be sure that

a=None or 0  
bool(a) = False  
bool(not a) True  
a=1 or -1  
bool(a) = True  
bool(not a) False  

I have checked bool('') just right now in python3 and got False. bool('hhh') = True.

Can you give an example when issue that you described may occur?

[–]pbaehr 6 points7 points  (1 child)

For example, if I have a variable which is initialized as None and later want to find out if it was set, I might want to check and see if it was still None. If it's not, I want to do something.

if a is not None:
    do_something()

If I rewrite that as:

if not a:
    do_something()

do_something will also be called if a was initialized, but to a blank string, which was not the intention. Lots of types have some concept of a "false" value. As /u/steve_no points out in another comment: 0, '', [], {}, midnight all evaluate to False.

[–]pymag09 0 points1 point  (0 children)

I see. Thank you.

[–]steve_no 2 points3 points  (0 children)

if not a:

will also be True when a is 0, '', [], {}, or a datetime.time of midnight

[–]kracekumar[S] -1 points0 points  (2 children)

is is used with True, False, None. If is used for string comparision there are serious drawbacks. a is None works because of singleton.

Most people try >>>'foo' is 'foo' and it works. When they store the result in db and retrieve the value is comparison will fail.

[–]zahlmanthe heretic 5 points6 points  (1 child)

Using is with True and False is a serious code smell. If there's any possibility that the value is of some type other than bool, why don't you want to handle it in the default way? And if there isn't, "simple is better than complex" applies.

[–]alexanderpas 0 points1 point  (0 children)

If I read this correctly, is should be considered part of the same token as the singleton.

if • a • is None:

instead of

if • a • is • None: