Python 3.8 (or CPython 3.8?) added the warning
SyntaxWarning: "is" with a literal. Did you mean "=="?
for the code 0 is 0
.
I understand the warning, and I know the difference between is
and ==
.
However, I also know that CPython caches the object for small integers and shares it in other cases as well.
(Out of curiosity, I just checked the code (header) again.
Small ints are cached in tstate->interp->small_ints
.
0
and 1
are even more special and are stored globally in _PyLong_Zero
and _PyLong_One
.
All new creations of int
s are via PyLong_FromLong
and that one first checks if it is a small integer and cached.)
Given this background, if you know you have an int
object, you could say that the check x is 0
should be safe, right? Also, you could derive that 0 is 0
should always be True
, right? Or is this an implementation detail of CPython and other interpreters do not follow this? Which interpreter does not follow this?
Despite this more generic question (which I'm just curious about), consider this more specific (example) code:
def sum1a(*args):
y = 0
for x in args:
if y is 0:
y = x
else:
y = y + x
return y
Vs:
def sum1b(*args):
y = 0
for x in args:
if y == 0:
y = x
else:
y = y + x
return y
Vs:
def sum1c(*args):
y = None
for x in args:
if y is None:
y = x
else:
y = y + x
if y is None:
return 0
return y
Vs:
def sum2(*args):
y = 0
for x in args:
y = y + x
return y
The reason I would sometimes prefer sum1*
over sum2
is that depending on the library, sum1*
can really be more efficient. E.g. if the argument is a Numpy/TensorFlow/PyTorch array, you really would save a (potentially costly) operation here.
The reason I would prefer sum1a
over sum1b
is that sum1b
would break on certain inputs. E.g. if the input is a Numpy array, this would not work.
Of course, you could use sum1c
instead of sum1a
. However, sum1a
is shorter. So this is nicer?
If the answer to the original question is that this should always work, and if you agree that sum1a
is the best option then, how would you get rid of the warning? Is there a simple workaround? In general, I can see that the warning can be useful. So I would not want to disable it completely. I just want to disable it for this specific statement.
Maybe I could wrap it up in a function:
def is_(a, b):
return a is b
And then just use if is_(y, 0): ...
. Does this work? Is that a good idea?
The Python Boolean type is one of Python's built-in data types. It's used to represent the truth value of an expression. For example, the expression 1 <= 2 is True , while the expression 0 == 1 is False . Understanding how Python Boolean values behave is important to programming well in Python.
By default, an object is considered true unless its class defines either a bool() method that returns False or a len() method that returns zero, when called with the object. Here are most of the built-in objects considered false: Constants defined to be false: None and False.
The Python bool() built-in function evaluates the Truthiness of an object. Values resolved to 0 are evaluated as False whereas anything else is evaluated as True. The common case of Python's bool() function is the conversion of values such that they can be evaluated in conditional statements.
Numbers. In Python, the integer 0 is always False , while every other number, including negative numbers, are True . In fact, under the hood, bool eans inherit from int egers.
No, it isn't. Case in point the Rust implementation for Python returns False
:
>>>>> 0 is 0
False
and this is not wrong, though I expect this to change in future versions (it has!).
is
calls id
who's only stipulation is that the id returned is unique and constant for a given object. Whether the source code representation for a number (0
here) maps to a distinct object or not is up for the implementation to define.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With