Tecnología · GUÍA PRÁCTICA
¿CSV pierde None frente al texto vacío en Python? Revise versión y contrato
La existencia de una opción de comillas no garantiza su comportamiento de lectura. Veinte controles locales separan fallos de análisis, pérdidas irreversibles al exportar y una alternativa limitada a texto o None.

En CPython3.12.14, escribir [None, ""] con csv.QUOTE_NOTNULL produjo un campo vacío sin comillas seguido de otro vacío entre comillas. Leerlo con la misma opción devolvió dos cadenas vacías. La constante existía, pero el lector instalado no conservaba la distinción.
Empiece por los bytes originales y las reglas de valores nulos declaradas por el productor. Si una exportación anterior ya representó igual un dato ausente y un texto intencionadamente vacío, cambiar opciones de lectura no permite reconstruir cuál era cuál. Conserve el archivo y vuelva a exportar los datos originales cuando esa diferencia importe.
1. Localice dónde desaparece la información
Mantenga intacto el archivo fuente. Examine con repr() una muestra pequeña sin datos sensibles para ver comas, comillas y finales de registro. En nuestra prueba, el recorrido con csv.writer predeterminado convirtió [None, ""] en ["", ""]: una pérdida al exportar. El escritor NOTNULL conservó dos campos distintos en el archivo, pero el lector 3.12 los fusionó: un límite de compatibilidad del analizador.
No convierta todas las cadenas vacías analizadas en None como reparación. En la muestra de dos campos, eso convirtió ambos en None y borró el vacío intencional. Un marcador sin reglas de escape también colisiona: representar None mediante <NULL> lo hizo indistinguible del texto real <NULL>.
2. Pruebe lector, escritor y filas de una columna
Muestre sys.version y escriba y lea una muestra con None, una cadena vacía y "001", usando exactamente las opciones de producción. La referencia de Python3.12 advierte que QUOTE_NOTNULL y QUOTE_STRINGS no afectan al lector; el cambio de lectura está documentado para 3.13. Solo ejecutamos 3.12.14.
Pruebe también una fila que contenga únicamente None. Nuestro escritor QUOTE_NOTNULL lanzó csv.Error: single empty field record must be quoted. Una fila con una cadena vacía se leyó como [""], mientras que un registro en blanco se leyó como []. Añadir comillas al nulo solo para evitar el error codificaría texto vacío en un contrato que distingue nulos mediante comillas.
3. Acuerde el formato antes de transformar
Con un lector moderno compatible, el contrato documentado de QUOTE_NOTNULL convierte un campo vacío sin comillas en None y mantiene los demás como cadenas. No restaura enteros ni objetos Python arbitrarios. QUOTE_STRINGS tiene sus propias conversiones numéricas y tampoco es un serializador general. Verifique todas las formas de fila admitidas en ambos extremos reales antes de adoptar cualquiera.
PostgreSQL COPY CSV muestra por qué importa el receptor: por defecto, un campo vacío sin comillas representa NULL y uno vacío entre comillas representa texto vacío. FORCE_NULL y FORCE_NOT_NULL pueden cambiar la interpretación. Es el comportamiento documentado de PostgreSQL, no una garantía universal de CSV. No ejecutamos una integración con base de datos ni Python3.13.
4. Una alternativa limitada si controla ambos extremos
Para un intercambio antiguo que solo permita str o None, nuestra capa de aplicación probada codifica None como el campo literal N y cada cadena como S seguida de todo su contenido original. Así, texto vacío se convierte en S; el texto N, en SN; y el texto real <NULL>, en S<NULL>. Pase esos campos a csv.writer normal: las comas, comillas y saltos internos siguen siendo responsabilidad de la capa CSV.
Al decodificar, convierta únicamente el campo exactamente igual a N en None. Si empieza por S, quite solo el primer carácter; rechace cualquier otro campo como etiqueta incorrecta. Rechace entradas que no sean cadenas ni None antes de escribir. Es un formato de aplicación nuevo y acordado explícitamente: no lo aplique a ciegas a CSV existentes ni suponga que COPY, pandas o una hoja de cálculo entiende las etiquetas.
5. Compruebe valores, tipos y forma de fila
Los 20 controles con aserciones cubrieron las dos pérdidas, la excepción del escritor con un único nulo, registros en blanco frente a un campo vacío, conversiones y colisiones de marcadores, y una matriz etiquetada de 13 valores. Incluyó None, texto vacío, "001", "0", textos parecidos a nulos o etiquetas, coma, comillas, salto interno y Unicode. Coincidieron tanto valores como tipos tras el recorrido.
Otros controles verificaron filas con un nulo, un texto vacío o dos nulos; rechazo de enteros y booleanos; y rechazo de etiquetas incorrectas o campos vacíos sin codificar. Esto demuestra el contrato indicado de texto o None en CPython3.12.14/Linux. No certifica otros entornos ni programas receptores. Mantenga una muestra representativa en cada frontera y vuelva a exportar, en vez de adivinar, si la distinción original ya desapareció.
