2013-05-22 14 views
32

Pracuję na ćwiczeniu 41 w learnpythonthehardway i wciąż otrzymuję błąd:Python3 Error: Błąd typu: obiekt nie może konwertować '' bajtów do STR niejawnie

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 

Używam python3 natomiast książek korzysta python2, więc wprowadziłem pewne zmiany. Oto skrypt:

#!/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") 

Co dokładnie robię źle tutaj? Dzięki!

+1

Na marginesie, to jest naprawdę z powrotem pomysł, aby nazwać plik 'urllib.py' podczas importowania z pakietu 'urllib'. Ale to nie jest twój problem. – abarnert

+0

Jako inna uwaga boczna: "dla słowa w urlopen (WORD_URL) .readlines():' jest głupie; po prostu "dla słowa w urlopen" (WORD_URL): '. Zakładam, że masz to z tutoriala, który śledzisz, co oznacza, że ​​samouczek nie jest napisany tylko dla python2, ale napisany dla bardzo starego python2 (lub przynajmniej przez kogoś, kto przywykł do bardzo starego python2), więc ... możesz chcieć znaleźć nowszy samouczek, jeśli chcesz nauczyć się pisać nowoczesny, idiomatyczny Python. – abarnert

Odpowiedz

27

zwraca obiekt bajtów, aby wykonać operacje na nim, należy najpierw przekonwertować go na str.

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

Aby uzyskać poprawne charset: How to download any(!) webpage with correct charset in python?

+4

Poza tym, że dane nie są w rzeczywistości UTF-8. Masz szczęście tutaj, ponieważ zdarza się, że jest ASCII, który jest ścisłym podzbiorem UTF-8, ale nie jest dobrze założyć, że wszędzie będziesz miał takie szczęście. – abarnert

14

W Pythonie 3, urlopen function zwracającą HTTPResponse obiekt, który działa jak pliku binarnego. Więc, kiedy to zrobić:

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

... skończyć z bandą bytes obiektów zamiast str obiektów. Więc kiedy to zrobić:

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

... skończyć się próbuje zastąpić ciąg "###" obrębie łańcucha result z bytes obiektu, zamiast str. Stąd błąd:

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

Odpowiedzią jest jawne odkodowanie słów tak szybko, jak je otrzymasz. Aby to zrobić, musisz znaleźć właściwe kodowanie z nagłówków HTTP. Jak to robisz?

W tym przypadku, czytam nagłówki, mogę powiedzieć, że jest to ASCII, a to oczywiście strona statyczna, więc:

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

Ale w prawdziwym życiu, zwykle trzeba napisać kod, który czyta nagłówki i dynamicznie je wylicza. Lub, lepiej, zainstaluj bibliotekę wyższego poziomu, taką jak requests, którą does that for you automatically.

0

jawnie przekonwertować typu BYTE „słowo” do łańcucha

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

powinno działać

Powiązane problemy