Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

258
Vistas
¿Por qué Python devuelve [15] para [0xfor x en (1, 2, 3)]?

Al ejecutar la siguiente línea:

 >>> [0xfor x in (1, 2, 3)]

Esperaba que Python devolviera un error.

En su lugar, el REPL devuelve:

[15]

¿Cuál puede ser la razón?

over 4 years ago · Hanz Gallego
3 Respuestas
Responde la pregunta

0

TL;DR

Python lee la expresión como [0xf or (x in (1, 2, 3))] , porque:

  1. El tokenizador de Python .
  2. Precedencia de operadores .

Nunca genera NameError gracias a la evaluación de cortocircuito : si la expresión que le queda al operador or es un valor real, Python nunca intentará evaluar el lado derecho.

Análisis de números hexadecimales

Primero, tenemos que entender cómo Python lee los números hexadecimales.

En la enorme función tok_get de tokenizer.c , nosotros:

  1. Encuentre el primer 0x .
  2. Siga leyendo los siguientes caracteres siempre que estén en el rango de 0-f.

El token analizado, 0xf (ya que "o" no está en el rango de 0-f), finalmente pasará al analizador PEG, que lo convertirá al valor decimal 15 (consulte el Apéndice A).

Todavía tenemos que analizar el resto del código, or x in (1, 2, 3)] , que queda como con el siguiente código:

 [15 or x in (1, 2, 3)]

Precedencia del operador

Debido a que in tiene mayorprecedencia de operadores que or , podríamos esperar que x in (1, 2, 3) se evalúe primero.

Esa es una situación problemática, ya que x no existe y generará un NameError .

or es perezoso

Afortunadamente, Python admite la evaluación de cortocircuito como or es un operador perezoso: si el operando de la izquierda es equivalente a True , Python no se molestará en evaluar el operando de la derecha.

Podemos verlo usando el módulo ast :

 parsed = ast.parse('0xfor x in (1, 2, 3)', mode='eval') ast.dump(parsed)

Producción:

 Expression( body=BoolOp( op=Or(), values=[ Constant(value=15), # <-- Truthy value, so the next operand won't be evaluated. Compare( left=Name(id='x', ctx=Load()), ops=[In()], comparators=[ Tuple(elts=[Constant(value=1), Constant(value=2), Constant(value=3)], ctx=Load()) ] ) ] ) )

Entonces la expresión final es igual a [15] .


Apéndice A: El analizador PEG

En la función parsenumber_raw de parsenumber_raw , podemos encontrar cómo Python trata los ceros iniciales:

 if (s[0] == '0') { x = (long)PyOS_strtoul(s, (char **)&end, 0); if (x < 0 && errno == 0) { return PyLong_FromString(s, (char **)0, 0); } }

PyOS_strtoul está en Python/mystrtoul.c .

Dentro de mystrtoul.c, el analizador analiza un carácter después de 0x . Si es un carácter hexadecimal, Python establece que la base del número sea 16:

 if (*str == 'x' || *str == 'X') { /* there must be at least one digit after 0x */ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) { if (ptr) *ptr = (char *)str; return 0; } ++str; base = 16; } ...

Luego analiza el resto del número siempre que los caracteres estén en el rango de 0-f:

 while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) { if (ovlimit > 0) /* no overflow check required */ result = result * base + c; ... ++str; --ovlimit; }

Eventualmente , establece el puntero para señalar el último carácter que se escaneó, que es un carácter más allá del último carácter hexadecimal:

 if (ptr) *ptr = (char *)str;

Gracias

  • CSI_Tech_Dept de reddit por remitirme a la sección correcta en el archivo tokenizer.c.
  • El tuit original .
over 4 years ago · Hanz Gallego Denunciar

0

Como han explicado otros, es solo el número hexadecimal 0xf seguido del operador or . Los operadores generalmente no necesitan espacios circundantes, a menos que sea necesario para evitar la ambigüedad. En este caso, la letra o no puede formar parte de un número hexadecimal, por lo que no hay ambigüedad. Consulte la sección sobre espacios en blanco en la referencia del lenguaje Python.

El resto de la línea no se evalúa debido a la evaluación de cortocircuito, aunque, por supuesto, se analiza y compila.

Usando ese mismo "truco", puede escribir un código de Python ofuscado de manera similar que no arroja excepciones, por ejemplo:

 >>> 0xbin b'in' False >>> 0xbis 1000 False >>> 0b1and 0b1is 0b00 False >>> 0o1if 0b1else Oy1then 1
over 4 years ago · Hanz Gallego Denunciar

0

Otras respuestas ya dicen qué sucede exactamente. Pero para mí, la parte interesante fue que el operador se reconoce incluso sin espacios en blanco entre el número y este. En realidad, mi primer pensamiento fue "Wow, Python tiene un analizador extraño".

Pero antes de juzgar con demasiada dureza, tal vez debería preguntarles a mis otros amigos qué piensan:

Perl:

 $ perl -le 'print(0xfor 3)' 15

Lúa:

 $ lua5.3 -e 'print(0xfor 4)' 15

Awk no tiene or , pero tiene in :

 $ awk 'BEGIN { a[15]=1; print(0x0fin a); }' 1

¿Rubí? (Realmente no lo sé, pero supongamos):

 $ ruby -e 'puts 0x0for 5' 15

Sí, FWIW, Python no está solo, todos esos otros lenguajes de tipo script también reconocen los operadores alfabéticos incluso si se pegan inmediatamente al reverso de una constante numérica.

over 4 years ago · Hanz Gallego Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda