web-dev-qa-db-fra.com

Écriture d'un fichier .CSV dans Python qui fonctionne pour les deux Python 2.7+ et Python 3.3+ dans Windows)

EDIT: Je l'ai mis dans le titre, mais je viens de réaliser que je ne l'ai pas mentionné dans le corps. Cela semble être spécifique à Windows.

J'ai du mal à écrire une sortie en utilisant le module csv Python dans un script qui fonctionne avec les deux Python 2.7 et 3.3.

Essayez d'abord ce qui fonctionne comme prévu dans Python 2.7:

with open('test.csv', 'wb') as csv_file:
    writer = csv.DictWriter(csv_file, ['header1', 'header2'])
    writer.writeheader()
    for item in items:
        writer.writerow(item)

Cependant, lorsque cette même chose est exécutée dans Python 3.3 vous vous retrouvez avec:

TypeError: 'str' does not support the buffer interface

Je change donc 'wb' à 'wt' et il s'exécute, mais maintenant j'ai une ligne vierge supplémentaire toutes les deux lignes du fichier.

Pour corriger cela, je change:

with open('test.csv', 'wt') as csv_file:

à:

with open('test.csv', 'wt', newline='') as csv_file:

Mais maintenant, ça casse Python 2.7:

TypeError: 'newline' is an invalid keyword argument for this function

Je sais que je pourrais simplement faire quelque chose comme:

try:
    with open('test.csv', 'wt', newline='') as csv_file:
        writer = csv.DictWriter(csv_file, ['header1', 'header2'])
        writer.writeheader()
        for item in items:
            writer.writerow(item)
except TypeError:
    with open('test.csv', 'wb') as csv_file:
        writer = csv.DictWriter(csv_file, ['header1', 'header2'])
        writer.writeheader()
        for item in items:
            writer.writerow(item)

Cependant, cela a une duplication sérieusement mauvaise.

Quelqu'un at-il une façon plus propre de le faire?

EDIT: Les données de test sont simples et n'ont pas de nouvelles lignes ou quoi que ce soit:

items = [{'header1': 'value', 'header2': 'value2'},
         {'header1': 'blah1', 'header2': 'blah2'}]
15
Tamerz

J'ai essayé plusieurs façons. Pour autant que je sache, simple en utilisant 'w' pourrait être une solution:

with open('test.csv', 'w') as csv_file:
    writer = csv.DictWriter(csv_file, fieldnames=['header1', 'header2'], lineterminator='\n')
    # write something
6
skyline75489

Voici un moyen générique plus simple:

import sys

if sys.version_info[0] == 2:  # Not named on 2.6
    access = 'wb'
    kwargs = {}
else:
    access = 'wt'
    kwargs = {'newline':''}

with open('test.csv', access, **kwargs) as csv_file:
    writer = csv.DictWriter(csv_file, ['header1', 'header2'])
    writer.writeheader()
    for item in items:
        writer.writerow(item)

Le principe ici n'est pas d'essayer de combattre les différences entre Python 2 et 3 mais d'avoir du code conditionnel. Vous ne pouvez aller jusque-là en écrivant du code sans ce genre de test, tôt ou tard vous devra tester la version Python.

8
cdarke