【问题标题】:TypeError with exec()带有 exec() 的类型错误
【发布时间】:2017-11-17 04:40:38
【问题描述】:

我正在尝试制作一个根据用户输入绘制某些线条的程序。

#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 个字母时才有效。但如果我尝试输入多个字母,例如短语“hello”,则会出现此错误

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() 不太了解,我一直在努力查找有关它的资料,这是一个项目,我真的没有太多时间。

如果有任何问题,或者你不明白我想要完成什么,请告诉我。我有点绝望。

谢谢

【问题讨论】:

    标签: python-3.x function typeerror


    【解决方案1】:

    您的问题不在于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 将海龟方法及其参数绑定在一起。

    【讨论】:

    • 感谢您的反馈和帮助,我的项目现在运行顺利。
    猜你喜欢
    • 2018-09-20
    • 2019-04-27
    • 1970-01-01
    • 2020-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    相关资源
    最近更新 更多