From: Stefan Schwarzer on
Hi DG,

On 2010-08-06 14:28, DG wrote:
> I've always thought of it as you don't compare strings with "is", you
> *should* use == The reasoning is that you don't know if that string
> instance is the only one in memory. I've heard as an implementation
> detail, since strings are immutable, that Python will only create one
> actual instance and just assign new references to it (your first x is
> y example), but to compare equality it just makes sense to use "==",
> not to ask if it is the same object in memory.

Yes, you'd usually use == to compare strings. The use in the
post presumably was to show the behavior when you use `is`;
I guess it wasn't meant as an example for production code. :)

I can imagine a case where you might want to compare a
string with `is`:

FORWARD = "forward"
BACKWARD = "backward"

...

def func(direction=FORWARD):
if direction is FORWARD:
...
elif direction is BACKWARD:
...
else:
...

in case you expect people to specifically use the constants
you provided in the module. Here, the fact that FORWARD
actually is the string "forward" might be considered an
implementation detail. Using a string instead of an
`object()` has the advantage that it makes usage in error
messages easier.

Actually, I've never seen such a use, as far as I remember.
What do other people here think? Is the code above, which
compares strings with `is`, bad style, and if yes, why? How
would you write the code instead?

> Plus, I believe the
> "==" operator will check if the variables point to the same object.

No, that's what `is` is for.

> Using is/is not with None works well, because I believe there will
> always only be 1 None object.

Yes, and it avoids subtle bugs if someone overwrites `__eq__`
in some class:

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

Stefan
From: Peter Pearson on
On Fri, 06 Aug 2010 15:37:04 +0200, Stefan Schwarzer wrote:
[snip]
> I can imagine a case where you might want to compare a
> string with `is`:
>
> FORWARD = "forward"
> BACKWARD = "backward"
>
> ...
>
> def func(direction=FORWARD):
> if direction is FORWARD:
> ...
> elif direction is BACKWARD:
> ...
> else:
> ...
>
> in case you expect people to specifically use the constants
> you provided in the module. Here, the fact that FORWARD
> actually is the string "forward" might be considered an
> implementation detail. Using a string instead of an
> `object()` has the advantage that it makes usage in error
> messages easier.
>
> Actually, I've never seen such a use, as far as I remember.
> What do other people here think? Is the code above, which
> compares strings with `is`, bad style, and if yes, why? How
> would you write the code instead?

Hey, that's a cute example, but . . . what a trap! Is it
possible to document the use-the-object-not-the-string requirement
loudly enough that people won't get caught?

--
To email me, substitute nowhere->spamcop, invalid->net.
From: Terry Reedy on
On 8/6/2010 5:27 AM, Richard D. Moores wrote:

> So there would be a different implementation for each operating
> system? One for Windows, one for linux? Or one for Vista and one for
> XP? I'm just trying to clarify what is meant by "implementation".

Different version of CPython (that string caching bit has changed in the
past) and CPython versus Jython, PyPy, IronPython, Cython, etc.

--
Terry Jan Reedy

From: Stefan Schwarzer on
Hello Peter,

On 2010-08-06 19:20, Peter Pearson wrote:
> On Fri, 06 Aug 2010 15:37:04 +0200, Stefan Schwarzer wrote:
> [snip]
>> I can imagine a case where you might want to compare a
>> string with `is`:
>>
>> FORWARD = "forward"
>> BACKWARD = "backward"
>>
>> ...
>>
>> def func(direction=FORWARD):
>> if direction is FORWARD:
>> ...
>> elif direction is BACKWARD:
>> ...
>> else:
>> ...
>> [...]

> Hey, that's a cute example,

Thanks!

> but . . . what a trap! Is it
> possible to document the use-the-object-not-the-string requirement
> loudly enough that people won't get caught?

That's a good question, actually that's the nagging problem
I also have with the approach.

In production code I might write

# Use _these_ objects to indicate directions, not string
# constants with the same value.
FORWARD = "forward"
BACKWARD = "backward"

However, that won't help if people import the module and see
the strings under "global data" and so assume they're "just
strings". Moreover, if you have to write such a comment for
every use of the idiom the conciseness of the approach
vanishes.

Another view at the matter would be to let clients of the
module find out their mistake by unit tests. But of course
that's somewhat doubtful as the intention should be to write
robust instead of bug-inviting code.

I wonder if there's a way to have both the "cuteness" of the
string constants _and_ more robustness.

Stefan
From: Ethan Furman on
Stefan Schwarzer wrote:
> Hello Peter,
>
> On 2010-08-06 19:20, Peter Pearson wrote:
>> On Fri, 06 Aug 2010 15:37:04 +0200, Stefan Schwarzer wrote:
>> [snip]
>>> I can imagine a case where you might want to compare a
>>> string with `is`:
>>>
>>> FORWARD = "forward"
>>> BACKWARD = "backward"
>>>
>>> ...
>>>
>>> def func(direction=FORWARD):
>>> if direction is FORWARD:
>>> ...
>>> elif direction is BACKWARD:
>>> ...
>>> else:
>>> ...
>>> [...]
>
>> Hey, that's a cute example,
>
> Thanks!
>
>> but . . . what a trap! Is it
>> possible to document the use-the-object-not-the-string requirement
>> loudly enough that people won't get caught?
>
> That's a good question, actually that's the nagging problem
> I also have with the approach.
>
> In production code I might write
>
> # Use _these_ objects to indicate directions, not string
> # constants with the same value.
> FORWARD = "forward"
> BACKWARD = "backward"
>
> However, that won't help if people import the module and see
> the strings under "global data" and so assume they're "just
> strings". Moreover, if you have to write such a comment for
> every use of the idiom the conciseness of the approach
> vanishes.
>
> Another view at the matter would be to let clients of the
> module find out their mistake by unit tests. But of course
> that's somewhat doubtful as the intention should be to write
> robust instead of bug-inviting code.
>
> I wonder if there's a way to have both the "cuteness" of the
> string constants _and_ more robustness.
>
> Stefan

Instead of using 'is' use '=='. Maybe not as cute, but definitely more
robust!

~Ethan~