2013-05-22 29 views
32

Ich arbeite an Übung 41 in learnpythonthehardway und halten Sie die Störung zu erhalten:Python3 Fehler: Typeerror: Kann nicht ‚Bytes‘ konvertieren Objekt auf str implizit

Traceback (most recent call last): 
    File ".\url.py", line 72, in <module> 
    question, answer = convert(snippet, phrase) 
    File ".\url.py", line 50, in convert 
    result = result.replace("###", word, 1) 
TypeError: Can't convert 'bytes' object to str implicitly 

ich python3 verwende, während die Bücher python2 verwendet, also habe ich ein paar Änderungen vorgenommen. Hier ist das Skript:

#!/usr/bin/python 
# Filename: urllib.py 

import random 
from random import shuffle 
from urllib.request import urlopen 
import sys 

WORD_URL = "http://learncodethehardway.org/words.txt" 
WORDS = [] 

PHRASES = { 
      "class ###(###):": 
       "Make a class named ### that is-a ###.", 
      "class ###(object):\n\tdef __init__(self, ***)" : 
       "class ### has-a __init__ that takes self and *** parameters.", 
      "class ###(object):\n\tdef ***(self, @@@)": 
       "class ### has-a funciton named *** that takes self and @@@ parameters.", 
      "*** = ###()": 
       "Set *** to an instance of class ###.", 
      "***.*** = '***'": 
       "From *** get the *** attribute and set it to '***'." 
} 

# do they want to drill phrases first 
PHRASE_FIRST = False 
if len(sys.argv) == 2 and sys.argv[1] == "english": 
    PHRASE_FIRST = True 

# load up the words from the website 
for word in urlopen(WORD_URL).readlines(): 
    WORDS.append(word.strip()) 

def convert(snippet, phrase): 
    class_names = [w.capitalize() for w in 
        random.sample(WORDS, snippet.count("###"))] 
    other_names = random.sample(WORDS, snippet.count("***")) 
    results = [] 
    param_names = [] 

    for i in range(0, snippet.count("@@@")): 
     param_count = random.randint(1,3) 
     param_names.append(', '.join(random.sample(WORDS, param_count))) 

    for sentence in snippet, phrase: 
     result = sentence[:] 

     # fake class names 
     for word in class_names: 
      result = result.replace("###", word, 1) 

     # fake other names 
     for word in other_names: 
      result = result.replace("***", word, 1) 

     # fake parameter lists 
     for word in param_names: 
      result = result.replace("@@@", word, 1) 

     results.append(result) 

    return results 

# keep going until they hit CTRL-D 
try: 
    while True: 
     snippets = list(PHRASES.keys()) 
     random.shuffle(snippets) 

     for snippet in snippets: 
      phrase = PHRASES[snippet] 
      question, answer = convert(snippet, phrase) 
      if PHRASE_FIRST: 
       question, answer = answer, question 

      print(question) 

      input("> ") 
      print("ANSWER: {}\n\n".format(answer)) 
except EOFError: 
    print("\nBye") 

Was genau mache ich hier falsch? Vielen Dank!

+1

Als Randnotiz funktionieren soll, ist es eine wirklich zurück Idee ist, eine Datei zu nennen 'urllib.py' wenn Sie importieren aus dem 'urllib'-Paket. Aber das ist nicht dein Problem hier. – abarnert

+0

Als eine weitere Randnotiz, 'für das Wort in URL (WORD_URL) .readlines():' ist dumm; tun Sie einfach 'for word in urlopen (WORD_URL):'. Ich gehe davon aus, dass Sie das aus dem Tutorial, das Sie folgen, haben, was bedeutet, dass das Tutorial nicht nur für python2 geschrieben ist, sondern für sehr alte Python2 geschrieben wurde (oder zumindest von jemandem, der sehr alt python2 gewohnt ist), also ... Vielleicht möchten Sie ein neueres Tutorial finden, wenn Sie lernen möchten, wie man modernes, idiomatisches Python schreibt. – abarnert

Antwort

27

urlopen() Gibt ein bytes-Objekt zurück, um String-Operationen auszuführen. Sie sollten es zuerst in str konvertieren.

for word in urlopen(WORD_URL).readlines(): 
    WORDS.append(word.strip().decode('utf-8')) # utf-8 works in your case 

Um die richtige charset zu erhalten: How to download any(!) webpage with correct charset in python?

+4

Außer, dass die Daten nicht wirklich UTF-8 sind. Sie haben Glück, weil es sich um ASCII handelt, was eine strenge Untermenge von UTF-8 ist, aber es ist nicht gut anzunehmen, dass Sie überall so viel Glück haben werden. – abarnert

14

In Python 3, die urlopen function gibt ein HTTPResponse Objekt, das wie eine Binärdatei handelt. Also, wenn Sie dies tun:

for word in urlopen(WORD_URL).readlines(): 
    WORDS.append(word.strip()) 

... Sie am Ende mit einem Bündel von bytes Objekten anstelle von str Objekten. Also, wenn Sie dies tun:

result = result.replace("###", word, 1) 

... Sie am Ende versuchen, die Zeichenfolge "###" innerhalb der Zeichenfolge result mit einem bytes Objekt zu ersetzen, statt ein str. Daher der Fehler:

TypeError: Can't convert 'bytes' object to str implicitly 

Die Antwort ist, die Wörter explizit zu dekodieren, sobald Sie sie erhalten. Um dies zu tun, müssen Sie die richtige Kodierung aus den HTTP-Headern herausfinden. Wie machst du das?

In diesem Fall habe ich gelesen, die Header, kann ich sagen, dass es ASCII ist, und es ist offensichtlich eine statische Seite, so:

for word in urlopen(WORD_URL).readlines(): 
    WORDS.append(word.strip().decode('ascii')) 

Aber im wirklichen Leben, müssen Sie in der Regel Code schreiben, der liest Header und dynamisch es aus. Oder, besser, installieren Sie eine höhere Bibliothek wie requests, die does that for you automatically.

0

Explizit umwandeln Byte Typ ‚Wort‘ in Zeichenfolge

result = result.replace("###", sre(word), 1) 

es

Verwandte Themen