The problem is is. Is it not?
Algunos, por alguna razón, hacen esto:
Y después, cuando ven esto, se sorprenden:
Se sorprenden porque "2 es 2" es más intuitivo que "1000 no es 1000". Podría atribuirlo a una tendencia innata al platonismo, pero en realidad es porque is
no es eso.
El operador is
es (en CPython) apenas una comparación de direcciones de memoria. Si los objetos a
y b
son el mismo cacho de memoria, entonces "son" el otro. Como python crea de antemano una cantidad de enteros pequeños, cada 2 que creás no es un nuevo 2, sino otra vez el 2 de la última vez.
Esto funciona por dos motivos:
Los enteros son solo lectura. Podés tener muchas variables que "contienen" el mismo 2, porque no lo pueden romper.
En python, la asignación es tan sólo crear aliases. No se hace una copia de 2 cuando se hace
a = 2
, solamente se dice "a es otro nombre para este 2 que tengo acá".
Esto sorprende a la gente que viene de otros lenguajes, por ejemplo C o C++. En esos lenguajes, una variable int a
nunca usaría la misma memoria que int b
porque justamente, una variable es un pedazo de memoria, y se puede cambiar el contenido. En C y C++, los enteros son mutables. Este 2 no es ese 2, a menos que lo hagas intencionalmente con punteros.
De hecho, la forma en que la asignación funciona en python lleva a otras sorpresas que son más interesantes en la vida real. Por ejemplo:
Eso no sorprende nada. Ahora, hagamos un pequeño cambio:
>>> def f(l=[]): ... l.append('x') ... return l ... >>> f() ['x'] >>> f() ['x', 'x'] >>> f() ['x', 'x', 'x']
Y eso sí es sorprendente, si no lo esperabas. Sucede porque las listas son mutables. El argumento por default se define cuando la función se define, y cada vez que llamás f()
estás usando y devolviendo la misma l
. Antes, también usábamos siempre la misma s
pero como los strings son inmutables, nunca cambiaba, y devolvíamos una nueva cada vez.
Podés comprobar que no te miento, obviamente que usando is
. Y ya que estamos, eso no es un problema para listas. Es un problema para los objetos de cualquier clase que vos definas, a menos que los hagas inmutables. Así que seamos cuidadosos con los argumentos por defecto, ¿ok?
Volviendo al problema original de que 1000 is not 1000
, lo sorprendente es que en realidad, no es interesante. Los enteros son fungibles. No te importa que sea el mismo entero, solo que sean iguales.
Comprobar identidad de enteros es como si me prestaras $1 y cuando te lo devuelvo, en vez de ver si es una moneda de $1, te fijaras si es la misma moneda. Simplemente no importa. Lo que queres es un 2, un 1000 o una moneda de $1.
Además, el reultado de 2 is 2
depende de la implementación de python. No hay motivo, en realidad, mas allá de una optimización, para que sea True
.
Esperando que esto aclare el tema, les dejo un último fragmento de código:
.. code-block:: pycon
>>> a = float('NaN') >>> a is a True >>> a == a False
UPDATE: Muchos comentarios iteresantes en reddit y una continuación chiquita acá
This is actually an issue in PyCharm, the JetBrains IDE for Python, which (from what I can see) will always nudge you to use "is" for any integer comparison, as it's "more readable" (which it is, but correctness will always trump readability).
BTW, the "bunch of small integers" is exactly 256, at least on Windows.
I use PyCharm extensively, and I've never seen it suggest the "is" operator for integer comparison.
maybe you turned off some option? i'm pretty sure it does suggest it. EDIT: see http://lateral.netmanagers....
I think you're talking about the use of "and" or "or" instead of "&&" and "||".
Actually, I went back to check and I think what I meant is the warning "boolean variable check can be simplified" (under Settings -> Inspectors -> Python), i.e. if int(someVar) == 0
In those cases, PyCharm suggests to switch from == to "is".
Remind me not to lend you $1... :-)
Jaja, el último snippet es como un remate de standup.
What's the benefit of pre-creating all 8-bit integers?
You use them often, and creating objects is kinda expensive.
This is an excellent illustration of two of the most eye-popping WTFs Python has to offer. For a language that potentially has so much to offer beginners, total catastrophe gotchas like these simply shouldn't exist. A lot of us may well have a computer science background, but a language that comes so close to being incredibly useful without one shouldn't make it a requirement.
While I would not have called is "is", there is really little to be done about the mutable default argument issue without making it less useful, AFAICS