2016-01-24 50 views
0

我有一塊代碼從列表中選擇一個單詞並將其顯示在標籤上,用戶必須正確地重新輸入以便繼續前進。突然收到AttributeError

import random 
try: 
    import tkinter as tk 
except ImportError: 
    import Tkinter as tk 

WORDS = ['Games', 'Development', 'Keyboard', 'Speed', 'Typer', 'Anything', 
     'Alpha'] 
score = 0 

def choose_word(): 
    global word 
    entry.focus_set() 
    word = random.choice(WORDS) 
    label.config(text=str(word.lower())) 

def check_entry(event): 
    global score 
    if entry.get().lower() == word.lower(): 
     score += 1 
     print(score) 
    elif entry.get().lower() != word.lower(): 
     score -= 1 
     print(score) 
    choose_word() 
    entry.delete(0, tk.END) 

root = tk.Tk() 

label = tk.Label(root) 
entry = tk.Entry(root) 

label.pack() 
entry.pack() 

choose_word() 
root.bind('<Return>', check_entry) 
root.mainloop() 

自從我幾個月前開始研究它以來,我一直在使用此代碼貫穿所有版本的代碼。我一點也沒有改變它,直到現在它的工作狀況都很好。錯誤是:

Exception in Tkinter callback 
Traceback (most recent call last): 
    File "C:\Users\ernxs\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1549, in __call__ 
    return self.func(*args) 
    File "C:\Users\ernxs\Downloads\speedtypr\Speedtypr FINAL\speedtyper.pyw", line 685, in choose_word 
    label.config(text=str(word.lower())) 
AttributeError: 'generator' object has no attribute 'lower' 

上週我注意到這個錯誤,因爲它很少發生,但現在我不能讓過去的第一個字,沒有它拋出這個錯誤。我的代碼在過去幾個月中經歷了主要更改,但我已將這些功能和任何與它們相關的任何功能完全保留,我不知道爲什麼它在3個月內完美運行,現在已停止工作。

我試過上面的代碼,它完美的工作,但是當我在完整的程序中運行它時,儘管沒有其他與我提到的功能有關的錯誤,但仍然得到錯誤。

我試過包括更我的節目(我希望是不要太多),但它仍然不會拋出同樣的錯誤:

try: 
    import tkinter as tk 

except ImportError: 
    import Tkinter as tk 

import time 
import random 

correct_words = [] 
WORDS = ['Basic', 'Christmas', 'Summer', 'Sports', 'Winter', 'Negative', 
     'Beach', 'Country', 'Christmas', 'Food', 'Games', 'Music', 'Family'] 

time_score = 0 
word_count = 0 
max_words = 12 
skips = 0 
total_words = 0 
words_found = 0 

def end_game(): 
    root.destroy() 
def choose_word(): 
    global word, start_time 
    go_btn.pack_forget() 
    start_time = time.time() 
    entry.focus_set() 
    if word_count < max_words: 

     word = random.choice(WORDS) 

     label.config(text=str(word.lower())) 
     time_score_label.config(text="Time: " + str(time_score) + "s")  

    else: 
     end_game() 

def check_entry(event): 
    if entry.get().lower() == word.lower(): 
     update_right() 

    elif entry.get().lower() != word.lower(): 
     update_wrong() 

    if len(entry.get()) < 1: 
     update_skip() 

    update_time()  
    choose_word() 
    entry.delete(0, tk.END) 

def update_time(): 
    global time_score 
    time_score += time.time() - start_time 
    time_score = round(time_score,2) 

def update_skip(): 
    global skips 
    skips += 1 
    skip_counter.config(text="Skips: " + str(skips)) 
    wrong_label.config(text="SKIPPED!", fg='red') 
    time_score_label.config(text="Time: " + str(time_score) + "s") 

def update_right(): 
    global word_count, words_found 

    word_count += 1 
    words_found += 1 
    WORDS.remove(word) 
    correct_words.append(word) 

    time_score_label.config(text="Time: " + str(time_score) + "s") 
    word_counter.config(text="Words: " + str(word_count)) 
    wrong_label.config(text="") 

def update_wrong():  
    wrong_label.config(text="WRONG!", fg='red') 
    time_score_label.config(text="Time: " + str(time_score) + "s") 

def display(): 
    for i in (label, time_score_label, word_counter, skip_counter, wrong_label, 
     entry): 
     i.pack() 
    choose_word() 

root = tk.Tk() 
go_btn = tk.Button(root, text="GO!", command=display, width=17) 
go_btn.pack() 
label = tk.Label(root, font=("Helvetica", 60)) 
time_score_label = tk.Label(root, text="Time: " + str(time_score) + 
           "s", font=('Helvetica', 14)) 
word_counter = tk.Label(root, text="Words: " + str(word_count), 
          font =("Helvetica", 14)) 
skip_counter = tk.Label(root, text="Skips: " + str(skips), 
          font =("Helvetica", 14)) 
wrong_label = tk.Label(root, text="", font =("Helvetica, 14")) 
entry = tk.Entry() 

root.bind("<Return>", check_entry) 
root.mainloop() 

這一切與此相關的功能和我無法重現錯誤。我不會發布我的完整程序,因爲它太長了,所以還有其他事情可以嘗試嗎?

+0

一個猜測是你重新定義名稱「單詞」的地方。將該函數中的名稱更改爲word_1或其他內容,看看是否有幫助。 –

+0

label.config(text = str(word.lower()))不使用從「WORDS」列表中選擇的「單詞」,不知何故它與「全局單詞」混淆,如果您重命名它,則不會收到錯誤。 – FatmaT

回答

0

的錯誤是在choose_word功能,與行:

word = random.choice(WORDS) 
label.config(text=str(word.lower())) 

看來用繩子WORDS,挑選一個列表工作。 word.lower()是一個字符串操作。我不知道爲什麼那裏加了str()電話。

該錯誤指示word不再是字符串,而是generator。 A generator就像一個列表,期望它一次返回一個值,並且不能反覆遍歷它。因此您需要關注WORDS。現在有什麼不同呢?也有可能random.choice已被更改。

說到這個功能,爲什麼要用global word?我不認爲這是造成問題,但它看起來不是很好的編程習慣。

+0

你引導我走向正確的方向,我從原始文本文件中導入列表,但在這裏我使用了一個列表。我刪除了'.lower()',看到數據被錯誤地讀入'WORDS'中。我會嘗試尋找任何東西。 – Ernxst

1

正如您所提到的,上述代碼似乎運行正常,但是您收到的錯誤告訴我們,在其他地方,您的代碼(或您從其他地方使用的代碼)也聲明瞭「全局單詞」並重新分配它發生器。

編輯:

閱讀下面留言觸發額外的想法;由於'word'沒有在check_entry中聲明,並且check_entry然後綁定到tkinter事件,所以這可能在沒有外部重新聲明「word」變量的情況下顯示該問題。我對Tkinter的代碼庫並不熟悉,但根據它們如何觸發/存儲事件,可能會有一個代表「綁定」狀態的「單詞」的承諾返回(發生器的產出)調用。你可以通過check_entry功能中聲明「字」作爲全球檢驗這一理論,但我仍然強烈建議所提出的OOPier的解決方案,而不是該快捷方式,即使它的工作原理

我建議你重構使用在這裏避免使用全局變量來解決問題。見下文,但請注意,這不是一個完美的重構;你應該嘗試的TK間工作隔離到一個單獨的類按照良好做法:

try: 
    import tkinter as tk 

except ImportError: 
    import Tkinter as tk 

import time 
import random 


class MyProgram(object): 
    def __init__(self): 
     self.word = None 
     self.start_time = None 
     self.correct_words = [] 
     self.WORDS = ['Basic', 'Christmas', 'Summer', 'Sports', 'Winter', 'Negative', 
       'Beach', 'Country', 'Christmas', 'Food', 'Games', 'Music', 'Family'] 

     #self.WORDS = ["test"] 
     self.time_score = 0 
     self.word_count = 0 
     self.max_words = len(self.WORDS) 
     self.skips = 0 
     self.total_words = 0 
     self.words_found = 0 
     self.setup_tk_components() 

    def setup_tk_components(self): 
     self.go_btn = tk.Button(root, text="GO!", command=self.display, width=17) 
     self.go_btn.pack() 
     self.label = tk.Label(root, font=("Helvetica", 60)) 
     self.time_score_label = tk.Label(root, text="Time: " + str(self.time_score) + 
             "s", font=('Helvetica', 14)) 
     self.word_counter = tk.Label(root, text="Words: " + str(self.word_count), 
            font =("Helvetica", 14)) 
     self.skip_counter = tk.Label(root, text="Skips: " + str(self.skips), 
            font =("Helvetica", 14)) 
     self.wrong_label = tk.Label(root, text="", font =("Helvetica, 14")) 
     self.entry = tk.Entry() 

    @staticmethod 
    def end_game(): 
     root.destroy() 

    def choose_word(self): 
     self.go_btn.pack_forget() 
     self.start_time = time.time() 
     self.entry.focus_set() 
     if self.word_count < self.max_words: 

      self.word = random.choice(self.WORDS) 

      self.label.config(text=str(self.word.lower())) 
      self.time_score_label.config(text="Time: " + str(self.time_score) + "s") 
      self.entry.delete(0, tk.END) 
     else: 
      MyProgram.end_game() 

    def check_entry(self, event): 
     if self.entry.get().lower() == self.word.lower(): 
      self.update_right() 

     elif self.entry.get().lower() != self.word.lower(): 
      self.update_wrong() 

     if len(self.entry.get()) < 1: 
      self.update_skip() 

     self.update_time() 
     self.choose_word() 

    def update_time(self): 
     self.time_score += time.time() - self.start_time 
     self.time_score = round(self.time_score, 2) 

    def update_skip(self): 
     self.skips += 1 
     self.skip_counter.config(text="Skips: " + str(self.skips)) 
     self.wrong_label.config(text="SKIPPED!", fg='red') 
     self.time_score_label.config(text="Time: " + str(self.time_score) + "s") 

    def update_right(self): 
     self.word_count += 1 
     self.words_found += 1 
     self.WORDS.remove(self.word) 
     self.correct_words.append(self.word) 

     self.time_score_label.config(text="Time: " + str(self.time_score) + "s") 
     self.word_counter.config(text="Words: " + str(self.word_count)) 
     self.wrong_label.config(text="") 

    def update_wrong(self): 
     self.wrong_label.config(text="WRONG!", fg='red') 
     self.time_score_label.config(text="Time: " + str(self.time_score) + "s") 

    def display(self): 
     for i in (self.label, self.time_score_label, self.word_counter, self.skip_counter, self.wrong_label, self.entry): 
      i.pack() 
     self.choose_word() 

if __name__ == '__main__': 
    root = tk.Tk() 
    mp = MyProgram() 

    root.bind("<Return>", mp.check_entry) 
    root.mainloop() 
    print mp.correct_words 

編輯:

def asstr(): 
    global word 
    word = "WORD" 
def asint(): 
    global word 
    word = 1 

asstr() 
print word 
print word.lower() 
asint() 
print word 
print word.lower() 
:發生了什麼事,其中另一個功能改變我的字符串爲int的一個簡單的例子

輸出:

WORD 
word 
1 
Traceback (most recent call last): 
    ... 
AttributeError: 'int' object has no attribute 'lower' 
+0

我沒有看到'word'可以在'random.choice'指定一個新值和'test = str(word.lower())'之間重新分配。我同意'全球'可能會導致問題,但我對這個例子有懷疑。 – hpaulj

+0

正在拋出錯誤的word.lower()我相信是check_entry調用中的一個,它在tkinter中綁定,而不是在choose_word中的一個。因爲「單詞」在check_entry調用中未被綁定,它將在綁定觸發器(我認爲) –

+0

時持有一個生成器而不是一個單詞。這看起來與所述錯誤不一致。但是,這種間歇性的事件更可能發生在與事件有關的事情上。 – hpaulj