Soy un tipo de Unix, pero los participantes en mis clases de Python usan abrumadoramente Windows. Inevitablemente, cuando llegamos a hablar de trabajar con archivos en Python, alguien querrá abrir un archivo usando la ruta completa del mismo. Y acabarán escribiendo algo así:
filename = 'c:\abc\def\ghi.txt'
Pero cuando mis alumnos intentan abrir el archivo, descubren que Python les da un error, ¡indicando que el archivo no existe! En otras palabras, escriben:
for one_line in open(filename): print(one_line)
¿Cuál es el problema? Esto parece bastante estándar en Python, ¿no?
Recuerda que las cadenas en Python normalmente contienen caracteres. Esos caracteres son normalmente imprimibles, pero hay veces que se quiere incluir un carácter que no es realmente imprimible, como una nueva línea. En esos casos, Python (como muchos lenguajes de programación) incluye códigos especiales que insertarán el carácter especial.
El ejemplo más conocido es la nueva línea, también conocida como ‘\n’, o ASCII 10. Si quieres insertar una nueva línea en tu cadena de Python, entonces puedes hacerlo con ‘\n’ en el medio. Por ejemplo:
s = 'abc\ndef\nghi'
Cuando imprimamos la cadena, veremos:
>>> print(s)abcdefghi
¿Qué pasa si quieres imprimir una ‘\n’ literal en tu código? Es decir, ¿quieres una barra invertida, seguida de una «n»? Entonces tendrá que duplicar la barra invertida:El «\\N» en una cadena dará lugar a un solo carácter de barra invertida. La «n» siguiente será entonces normal. Por ejemplo:
s = 'abc\ndef\nghi'
Cuando decimos:
>>> print(s)abc\ndef\nghi
Es bastante conocido que hay que evitar esta traducción cuando se trabaja con \n. Pero, ¿qué otros caracteres lo requieren? Resulta que más de lo que muchos podrían esperar:
- \a – campana de alarma (ASCII 7)
- \b – retroceso (ASCII
- \f – avance de formulario
- \n – línea nueva
- \r – retorno de carro
- \t – tabulación
- \v – tabulador vertical
- \ooo – carácter con valor octal ooo
- \xhh – carácter con valor hexadecimal hh
- \N{nombre} – carácter Unicode {nombre}
- \uxxxx – carácter Unicode con valor hexadecimal de 16-valor hexadecimal de 16 bits xxxx
- \Uxxxxxxxx – Carácter Unicode con valor hexadecimal de 32 bits xxxxxxxx
En mi experiencia es muy poco probable que uses algunos de estos a propósito. Quiero decir, ¿cuándo fue la última vez que necesitó utilizar un carácter de alimentación de forma? ¿O un tabulador vertical? Lo sé – fue más o menos el mismo día que condujiste tu dinosaurio al trabajo, después de cavar un pozo en tu patio trasero para beber agua.
Pero casi cada vez que enseño Python – que es, todos los días – alguien en mi clase se topa con uno de estos caracteres por error. Esto se debe a que la combinación de las barras invertidas que utilizan estos caracteres y las barras invertidas que se utilizan en las rutas de Windows da lugar a inevitables, y frustrantes, errores.
¿Recuerdas esa ruta que mencioné al principio de la entrada del blog, que parece tan inocente?
filename = 'c:\abc\def\ghi.txt'
Contiene un carácter «\a». Lo que significa que cuando lo imprimimos:
>>> print(filename)c:bc\def\ghi.txt
¿Ves? La «\a» ha desaparecido, sustituida por un carácter de campana de alarma. Si tienes suerte.
Entonces, ¿qué podemos hacer con esto? Duplicar las barras invertidas, por supuesto. Sólo hay que duplicar las que se convertirían en caracteres especiales, a partir de la tabla que he reproducido más arriba: Pero vamos, ¿es realmente probable que recuerdes que «\f» es especial, pero «\g» no? Probablemente no.
Así que mi regla general, y lo que les digo a mis alumnos, es que siempre deben duplicar las barras invertidas en sus rutas de Windows. En otras palabras:
>>> filename = 'c:\abc\def\ghi.txt'>>> print(filename)c:\abc\def\ghi.txt
¡Funciona!
Pero espere: nadie quiere realmente recorrer sus nombres de ruta, duplicando cada barra invertida, ¿verdad? Por supuesto que no.
Ahí es donde las cadenas crudas de Python pueden ayudar. Pienso en las cadenas crudas de dos maneras diferentes:
- Lo que ves es lo que obtienes
- Doblar automáticamente las barras invertidas en las cadenas
De cualquier manera, el efecto es el mismo: todas las barras invertidas se duplican, por lo que todos estos molestos y extraños caracteres especiales desaparecen. Lo cual es genial cuando se trabaja con rutas de Windows.
Todo lo que tiene que hacer es poner una «r» antes de las comillas de apertura (simples o dobles):
>>> filename = r'c:\abc\def\ghi.txt'>>> print(filename)c:\abc\def\ghi.txt
Note que una «cadena cruda» no es realmente un tipo diferente de cadena en absoluto. Es sólo otra forma de introducir una cadena en Python. Si lo compruebas, type(filename) seguirá siendo «str», pero sus barras invertidas estarán todas duplicadas.
Línea inferior: Si está usando Windows, entonces debería escribir todas sus cadenas de nombres de ruta codificadas como cadenas crudas. Incluso si eres un experto en Python, puedo decirte por experiencia que a veces te encontrarás con este problema. E incluso para los mejores de nosotros, encontrar ese «\f» perdido en una cadena puede llevar mucho tiempo y ser frustrante.
PS: Sí, es cierto que los usuarios de Windows pueden evitar esto mediante el uso de barras inclinadas, como hacemos los de Unix. Pero mis alumnos encuentran que esto tiene un aspecto particularmente extraño, y por eso no lo veo como una solución de uso general.
¿Le ha gustado este artículo? Únase a más de 11.000 desarrolladores que reciben mi boletín semanal gratuito «Mejores desarrolladores». Cada lunes, recibirás un artículo como este sobre desarrollo de software y Python: