11
votes

Python 2 et 3 lecteur CSV

J'essaie d'utiliser le module CSV pour lire un fichier CSV UTF-8, et j'ai des problèmes pour créer un code générique pour Python 2 et 3 en raison de l'encodage.

Voici le code d'origine en python 2.7: P>

with codecs.open(filename, 'r', encoding='utf-8') as csvfile:
    csv_reader = csv.reader(csvfile, quotechar='\"')
    langs = next(csv_reader)[1:]
    for row in csv_reader:
        pass


7 commentaires

Donc, vous voulez que le code fonctionne inchangé à la fois sur Python 2.7 et 3? Probablement impossible, étant donné que tellement changé avec la manipulation des cordes, etc.


Est-il possible de spécifier le code de bloc pour Python 2 ou 3?


Vous pouvez vérifier sys.version et envelopper un si - else instruction autour de votre code, oui.


@Tim Pietzchker; Il est préférable de demander pardon que la permission.


Je pense que vous aviez le drapeau B dans le mauvais exemple, je l'ai changé.


@Jakobbowyer EAFP ne fonctionne que dans des fonctions nommées, pas dans les expressions génératrices. Ceci est intentionnel, que je peux dire parce que PEP 463 pour attraper en ligne était rejeté.


Alors que la recommandation "officielle" est de faire des CSV différemment dans Python 2 et Python 3, il y a un Nettoyant, plus élégant répertorié comme une réponse à un Similaire, Si ce n'est pas dupliquer, question .


3 Réponses :


17
votes

En effet, en Python 2, le fichier doit être ouvert en mode binaire, mais en mode Python 3 en mode texte. également dans Python 3 newline = '' code> devrait être spécifié (que vous avez oublié).

Vous devrez faire l'ouverture du fichier dans un bloc IF. P>

import sys

if sys.version_info[0] < 3: 
    infile = open(filename, 'rb')
else:
    infile = open(filename, 'r', newline='', encoding='utf8')


with infile as csvfile:
    ...


8 commentaires

Pouvez-vous faire avec sur une poignée de fichier?


@Tim: Ce n'est pas une poignée de fichier, c'est un objet de fichier et vous pouvez faire avec sur des objets de fichier. C'est exactement ce que vous faites lorsque vous faites avec ouvert (... .


Logique. Vous ne le voyez jamais vraiment comme ça, c'est toujours avec Open (...) dans les docs, mais de cette façon n'est pas à moitié mauvais - vous permet d'envelopper le ouvert () dans un ESSAYEZ Bloc et Catch> Fichier non trouvé etc. Avant de le remettre sur le bloc .


Ou, dans certaines situations, si sys.version <'3': Open = codecs.open .


@Agf: Ouais, cela peut travailler aussi. Codecs.Open et Python 3 Open ne sont pas exactement les mêmes, cependant, il y a donc des pièges subtils, mais cela fonctionnera souvent. En 2.6 et 2.7, vous pouvez faire à partir d'IO importer Ouvrir , cependant.


Le lecteur Python 2 CSV fonctionne uniquement avec ASCII, il suffit donc d'utiliser «R» ou «RB» à ouvrir uniquement une partie de la question.


Est-ce toujours la bonne approche, même avec six ou 2to3 et d'autres bibliothèques? Je viens de voir quel âge a cette réponse.


Pour autant que je sache, oui.



0
votes

Vieille question que je connais, mais je cherchais à faire ça. Juste au cas où quelqu'un vient sur ceci et pourrait le trouver utile.

C'est comme ça que j'ai résolu la mienne, merci Lennart Regèbre pour le conseil. : xxx

puis faites ce que vous devez faire: xxx


0 commentaires

2
votes

mise à jour forte>: tandis que le code de ma réponse d'origine fonctionne, je pose quand même un petit paquet sur https://pyposi.python.org/pypi/csv342 qui fournit une interface Python 3 comme une interface de Python 2. So indépendant de votre version Python, vous pouvez simplement faire un xxx pré> réponse originale forte>: Voici une solution que même avec Python 2 décode le texte sur les chaînes UNICODE et fonctionne par conséquent avec des codages autres que UTF-8. P>

Le code ci-dessous définit une fonction csv_rows () code> qui renvoie le contenu d'un fichier comme séquence de listes. Exemple d'utilisation: p> xxx pré>

Voici les deux variantes pour csv_rows () code>: un pour Python 3+ et un autre pour Python 2.6+. Pendant l'exécution, il choisit automatiquement la variante appropriée. utf8Recoder code> et Unicodereader code> sont des copies verbatim du Exemples de la documentation de la bibliothèque Python 2.7 . P>

import csv
import io
import sys


if sys.version_info[0] >= 3:
    # Python 3 variant.
    def csv_rows(csv_path, encoding, **keywords):
        with io.open(csv_path, 'r', newline='', encoding=encoding) as csv_file:
            for row in csv.reader(csv_file, **keywords):
                yield row

else:
    # Python 2 variant.
    import codecs

    class UTF8Recoder:
        """
        Iterator that reads an encoded stream and reencodes the input to UTF-8
        """
        def __init__(self, f, encoding):
            self.reader = codecs.getreader(encoding)(f)

        def __iter__(self):
            return self

        def next(self):
            return self.reader.next().encode("utf-8")


    class UnicodeReader:
        """
        A CSV reader which will iterate over lines in the CSV file "f",
        which is encoded in the given encoding.
        """

        def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
            f = UTF8Recoder(f, encoding)
            self.reader = csv.reader(f, dialect=dialect, **kwds)

        def next(self):
            row = self.reader.next()
            return [unicode(s, "utf-8") for s in row]

        def __iter__(self):
            return self


    def csv_rows(csv_path, encoding, **kwds):
        with io.open(csv_path, 'rb') as csv_file:
            for row in UnicodeReader(csv_file, encoding=encoding, **kwds):
                yield row


0 commentaires