2017-06-14 104 views
-2

我想製作一個程序,根據用戶輸入繪製某些行。類型錯誤與執行()

#import turtle program 
#called it cassy cause I was trying to come up with a fun name for an arrow 
that they call 'classic'. I tried ok. 
import turtle 
cassy = turtle.Turtle() 
cassy.shape('classic') 

#set's the window shape, so I can give myself more room 
#for reference, putting startx and y as none centers it 
turtle.setup(width=1200, height=600, startx=None, starty=None) 



#used to find the height of what the screen size is so I could figure out 
what it was set at. 
"""print(turtle.window_width()) 
print(turtle.window_height())""" 


#gives our wonderful circle a home (where it starts), to the right and 
middle of the box 
#old code (turtle.setworldcoordinates(-20, -20, 0, 20)) 
cassy.hideturtle() 
cassy.penup() 
cassy.goto(580, 0) 

#sets the turtle to be facing left 
cassy.left(180) 
cassy.showturtle() 
cassy.pendown() 

#as always, I gotta have that sweet sweet starting message. 
print("Welcome to the line generator!") 
print("To start, type in a letter") 


#using a dictionary function so I can assign each character a "Line" 
line = { 
    "a" : "cassy.left(20)", 
    "b" : "cassy.forward(20)", 
    "c" : "cassy.right(45)", 
    "d" : "cassy.right(70)",  
    "e" : "cassy.circle(10)", 
    "f" : "cassy.left(15)", 
    "g" : "cassy.forward(15)", 
    "h" : "cassy.left(60)", 
    "i" : "cassy.forward(10)", 
    "j" : "cassy.forward(55)", 
    "k" : "cassy.circle(50, 100)", 
    "l" : "cassy.right(80)", 
    "m" : "cassy.forward(35)", 
    "n" : "cassy.left(75)", 
    "o" : "cassy.forward(45)", 
    "p" : "cassy.right(5)", 
    "q" : "cassy.forward(100)", 
    "r" : "cassy.right(65)", 
    "s" : "cassy.forward(125)", 
    "t" : "cassy.left(25)", 
    "u" : "cassy.forward(150)", 
    "v" : "cassy.right(95)", 
    "w" : "cassy.forward(120)", 
    "x" : "cassy.circle(25, 175)", 
    "y" : "cassy.circle(5, 190)", 
    "z" : "cassy.forward(175)", 
    "0" : "cassy.right(20)", 
    "1" : "cassy.forward(210)", 
    "2" : "cassy.left(120)", 
    "3" : "cassy.forward(115)", 
    "4" : "cassy.forward(15)", 
    "5" : "cassy.circle(30, 150)", 
    "6" : "cassy.left(70)", 
    "7" : "cassy.right(40)", 
    "8" : "cassy.backward(30)", 
    "9" : "cassy.backward(130)" 
} 

#let's the user type in letters/numbers (and only those (unless I want to   
mix things up; we'll see)) 
while True: 
    draw = input("Type anything to draw! ") 

    #if statement to make sure that they only type in numbers or letters 
    if(draw.isalnum() == True): 

     #I can only assume that this executes the code inside the quotes 
     #but I haven't looked too deeply into what exec() does 
     exec(line.get(draw)) 

     #this seperates each character drawn by a space, for funsies (yes I know it's a weird thing to say) 
     cassy.penup() 
     cassy.forward(15) 
     cassy.pendown() 

    #else statement in case they type in other charaters that aren't numbers or letters 
    else: 
     print("Please only use letters or numbers.") 

好了,所以我知道這是一個很多的閱讀,但我真正的問題是這行代碼

exec(line.get(draw)) 

到目前爲止,當我在1個字母同時鍵入程序纔有效。但如果我嘗試並鍵入多個字母,比如那句「你好」它給了我這個錯誤

Traceback (most recent call last): 
    File "C:/Users/73059/Final Project/Final Project funstuffs.py", line 87, in <module> 
    exec(line.get(draw)) 
TypeError: exec() arg 1 must be a string, bytes or code object 

我真的不知道了很多關於函數的exec(),我已經一直在試圖看看它的東西,這是一個項目,我真的沒有太多時間。

如果有任何問題,或者你不明白我想完成什麼,請告訴我。我有點絕望。

感謝

回答

0

你的問題是不是真的與exec電話,但與價值你傳遞作爲參數。當您執行line.get(draw)時,可以在line字典中查找變量draw的值。如果該值不存在(因爲draw是多字符字符串,則不會),則會得到None。運行exec(None)會爲您提供TypeError

我有幾種解決此問題的方法。你想要遵循哪些可能取決於你的程序需要什麼樣的行爲。

首先,我建議使用括號索引字典,而不是get方法。這會將您從TypeError(從exec)得到的錯誤更改爲字典中的KeyError。這仍然是一個例外,但它至少可以更準確地指出問題的原因(查找的字符串不在字典中)。

下一個建議是在嘗試查找它之前檢查多字符字符串,並向用戶報告錯誤。你可以檢查len(draw)是否等於1,如果是的話只運行其餘的代碼。我會將這張支票放在您當前對字母數字字符進行檢查的地方。

下面是這兩個補丁會是什麼樣在一起:

while True: 
    draw = input("Type anything to draw! ") 

    if draw.isalnum() and len(draw) == 1: # check length, "== True" and parens were unneeded 
     exec(line[draw]) # use indexing instead of "get" to generate better exception types 

    else: 
     print("Please only enter a single letter or number at a time.") 

另外,如果你想允許更長的輸入(與輸入的每個字符被另案處理),你可以在你的代碼改過來循環而不是試圖一次性處理它們。這將是這個樣子:

while True: 
    draw = input("Type anything to draw! ") 

    if draw.isalnum(): # no length check needed in this version 

     for character in draw: # loop over characters 
      exec(line[character]) 

      cassy.penup()  # it's not clear if you want these lines inside the inner loop 
      cassy.forward(15) # if not, you can unindent them one level 
      cassy.pendown() 

    else: 
     print("Please only use letters or numbers.") 

雖然這應該工作,使用exec通常是編寫代碼一個糟糕的方式。更好的方法是將函數(或其他可調用對象)放入字典中,然後調用從索引中返回的值。您可以使用lambda關鍵字創建匿名功能。 Lambda函數有一些限制,但它們足夠滿足我們的需求。下面是你可能會看在字典中使用lambda表達式:

line = { 
    "a" : lambda: cassy.left(20), 
    "b" : lambda: cassy.forward(20), 
    "c" : lambda: cassy.right(45), 
    "d" : lambda: cassy.right(70),  
    "e" : lambda: cassy.circle(10), 
    "f" : lambda: cassy.left(15), 
    "g" : lambda: cassy.forward(15), 
    "h" : lambda: cassy.left(60), 
    "i" : lambda: cassy.forward(10), 
    "j" : lambda: cassy.forward(55), 
    "k" : lambda: cassy.circle(50, 100), 
    "l" : lambda: cassy.right(80), 
    "m" : lambda: cassy.forward(35), 
    "n" : lambda: cassy.left(75), 
    "o" : lambda: cassy.forward(45), 
    "p" : lambda: cassy.right(5), 
    "q" : lambda: cassy.forward(100), 
    "r" : lambda: cassy.right(65), 
    "s" : lambda: cassy.forward(125), 
    "t" : lambda: cassy.left(25), 
    "u" : lambda: cassy.forward(150), 
    "v" : lambda: cassy.right(95), 
    "w" : lambda: cassy.forward(120), 
    "x" : lambda: cassy.circle(25, 175), 
    "y" : lambda: cassy.circle(5, 190), 
    "z" : lambda: cassy.forward(175), 
    "0" : lambda: cassy.right(20), 
    "1" : lambda: cassy.forward(210), 
    "2" : lambda: cassy.left(120), 
    "3" : lambda: cassy.forward(115), 
    "4" : lambda: cassy.forward(15), 
    "5" : lambda: cassy.circle(30, 150), 
    "6" : lambda: cassy.left(70), 
    "7" : lambda: cassy.right(40), 
    "8" : lambda: cassy.backward(30), 
    "9" : lambda: cassy.backward(130) 
} 

while True: 
    draw = input("Type anything to draw! ") 

    if(draw.isalnum() == True): 

     for character in draw: # loop over characters 
      line[character]() # call the value looked up in the dict 

      cassy.penup() # it's not clear if you want these lines inside the inner loop 
      cassy.forward(15) # if not, you can unindent them one level 
      cassy.pendown() 

    else: 
     print("Please only use letters or numbers.") 

還有其他幾種方法,你可以使可調用,如使用functools.partial烏龜方法及其自變量綁定在一起。

+0

感謝您的反饋和幫助,我的項目現在運行順利。 – Benita