当用户在执行期间更改变量时,分配给该变量的所有 variables/functions 都不会更改为新值

When user changes variable during execution, not ALL variables/functions with that variable assigned change to the new value

标题可能看起来很吓人,但我仍然希望有人能帮助我解决我遇到的问题。好的,所以我创建了一个程序,如果有人按 "H"、"E"、"L"、"O"、"W"、[=46= 中的任意键],"D",相应的字母会打印在海龟图形中window。用户还可以使用 F1-F10 中的任意键更改字母的颜色,通过在键盘上键入 1-0 中的任意数字(0=10)来更改每个字母的粗细,用户甚至可以更改 "dimensions"(高度和宽度)从他们在开头设置的每个字母,通过键入 "K" 键并在显示的对话框中键入相应的值。用户更改这些值正是我遇到问题的地方。但首先,让我们向您展示我的程序代码:

" A simple typing program

Press "H" to draw an H
Press "E" to draw an E
Press "L" to draw a L
Press "O" to draw an O
Press "W" to draw a W
Press "R" to draw a R
Press "D" to draw a D
Press "ENTER" to go to the next line
Press "TAB" to make an indent
Press "BACKSPACE" to go backwards an indent
Press the "Up" or "Down" arrow keys to move the turtle up or down the canvas
Press "SPACE" to clear the canvas of your drawings
Press "ESC" to exit the program
Press any number from 1-0 on the key board (1 = 1, 0 = 10) to set the letter thickness
Press any key from F1-F10 to set a random color of the letter
(F1-F8 = colors, F9 = Custom Color, F10 = Original color)

That is all you need to know! Enjoy! """

from turtle import *
from math import *
from tkinter import *
from tkinter.colorchooser import *
import copy

# Function variables

space_width = 30 # Default value: 30
letter_height = 100 # Default value: 100
letter_width = 50 # Default value: 50



change = (input("Would you like to change the size of the letters from the defult value? y/any other input: "))

y = ("yes")
n = ("no")


if change in y:
    try:
        while True:
            try:
                letter_height = int(input("Enter a value from 1-170 to set the height of each letter in pixels: "))
                break
            except ValueError:
                print("That is not an integer! Please enter an integer from 1-170!")
        while letter_height > 170:
            try:
                letter_height = int(input("That value is too much. Please reenter a value from 1-170: "))
                while letter_height < 1:
                    letter_height = int(input("That value is too little. Please reenter a value from 1-170: "))
            except ValueError:
                print("That is not an integer! Please enter an integer from 1-170!")
        while letter_height < 1:
            try:
                letter_height = int(input("That value is too little. Please reenter a value from 1-170: "))
                while letter_height > 170:
                    letter_height = int(input("That value is too much. Please reenter a value from 1-170: "))
            except ValueError:
                print("That is not an integer! Please enter an integer from 1-170!")
        while True:
            try:
                letter_width = int(input("Enter a value from 1-170 to set the width of each letter in pixels: "))
                break
            except ValueError:
                print("That is not an integer! Please enter an integer from 1-170!")
        while letter_width > 170:
            try:
                letter_width = int(input("That value is too much. Please reenter a value from 1-170: "))
                while letter_width < 1:
                    letter_width = int(input("That value is too little. Please reenter a value from 1-170: "))
            except ValueError:
                print("That is not an integer! Please enter an integer from 1-170!")
        while letter_width < 1:
            try:
                letter_width = int(input("That value is too little. Please reenter a value from 1-170: "))
                while letter_width > 170:
                    letter_width = int(input("That value is too much. Please reenter a value from 1-170: "))
            except ValueError:
                print("That is not an integer! Please enter an integer from 1-170!")
            break
    except:
        input("That is not an answer! Please enter either y or n!: ")

elif change in n:
    space_width = 30 # Default value: 30
    letter_height = 100 # Default value: 100
    letter_width = 50 # Default value: 50

#The 'while' loop below will tell the user to choose a color name, but if the color is invalid, an exception is thrown, and the user must reenter a color name until a valid color name is entered. 

while True:
    try:
        pen_color=input("Enter a color name to set the pen color: ")
        pencolor(pen_color)
        break
    except:
        print("That is either not an available color or not a valid color name. Please reenter the name of another color or a valid one.")

def NewLetterDimensions():
    def NewLetterHeight():
        global letter_height
        letter_height = (numinput("New Letter Height", "Please set the new letter height: ", minval = 10, maxval = 170))
    def NewLetterWidth():
        global letter_width
        letter_width = (numinput("New Letter Width", "Please set the new letter width: ", minval = 10, maxval = 170))
    NewLetterHeight()
    NewLetterWidth()
    penup()
    goto(xcor(), ycor() +letter_height)
    pendown()
    listen()


angle_height = (sqrt(letter_width**2 + (letter_height/2)**2))
a = (degrees(acos(letter_width/angle_height)))
b = (90-a)
R_angle = (90+b)

D_angle = (90+(degrees(acos(letter_width/angle_height))))
Second_D_angle = ((90 - (D_angle-90)) + (90-(degrees(acos(letter_width/angle_height)))))
D_space_angle = (degrees(atan(letter_width/(letter_height/2))))
space_angle = (180 - R_angle)


def draw_space():
    # Add a space 30 pixels wide.
    penup()
    forward(space_width)
    pendown()

def move_turtle():
    # Pick up the turtle and move it to its starting location.
    penup()
    goto(-200, 100)
    pendown()

def draw_H():
    # Draw the left leg of H.
    # The turtle starts at the bottom left of the letter, pointing right.
    left(90)
    forward(letter_height)
    # Draw the bar of the H.
    # The turtle starts at the top of the left leg, pointing up.
    forward(-letter_height/2)
    right(90)
    forward(letter_width)
    # Draw the right leg of the H.
    # The turtle starts at the right side of the bar, pointing right.
    left(90)
    forward(letter_height/2)
    forward(-letter_height)
    right(90)
    # The H is drawn.
    # The turtle is in the top right, pointing right.
    draw_space()


def draw_E():
    # Draw an E.
    left(90)
    forward(letter_height)
    right(90)
    forward(letter_width)
    forward(-letter_width)
    right(90)
    forward(letter_height/2)
    left(90)
    forward(letter_width)
    forward(-letter_width)
    right(90)
    forward(letter_height/2)
    left(90)
    forward(letter_width)
    draw_space()

def draw_L():
    # Draw an L
    left(90)
    forward(letter_height)
    forward(-letter_height)
    right(90)
    forward(letter_width)
    draw_space()

def draw_O():
    # Draw an O
    forward(letter_width)
    left(90)
    forward(letter_height)
    left(90)
    forward(letter_width)
    left(90)
    forward(letter_height)
    left(90)
    forward(letter_width)
    draw_space()

def draw_newline():
    # This funtion will pick up the turtle and move it to a second line below HELLO
    penup()
    goto(xcor(), ycor() -letter_height-5)
    pendown()

def draw_W():
    # This function will draw a W
    left(105)
    forward(letter_height)
    backward(letter_height)
    right(40)
    forward(letter_height/2)
    right(131)
    forward(letter_height/2)
    left(141)
    forward(letter_height)
    right(165)
    penup()
    forward(letter_height)
    left(90)
    draw_space()

def draw_second_O():
    # This function will draw the O in "world"
    forward(letter_width)
    right(90)
    forward(letter_height)
    right(90)
    forward(letter_width)
    right(90)
    forward(letter_height)
    right(90)
    penup()
    forward(letter_width)
    right(90)
    forward(letter_height)
    left(90)
    draw_space()

def draw_R():
    # This function will draw an R
    left(90)
    forward(letter_height)
    right(90)
    forward(letter_width)
    right(90)
    forward(letter_height/2)
    right(90)
    forward(letter_width)
    left(R_angle)
    forward(angle_height)
    left(space_angle)
    draw_space()

def draw_D():
    # This function will draw a REAL D
    left(90)
    forward(letter_height)
    right(D_angle)
    forward(angle_height)
    right(Second_D_angle)
    forward(angle_height)
    left(90+D_space_angle)
    penup()
    forward(letter_width)
    draw_space()

def skip(x, y):
    penup()
    goto(x, y)
    pendown()

def back():
    penup()
    bk(letter_width + space_width)
    pendown()

def walk():
    penup()
    forward(letter_width + space_width)
    pendown()

def soar():
    penup()
    left(90)
    forward(letter_height + 5)
    right(90)
    pendown()

def fall():
    penup()
    right(90)
    forward(letter_height + 5)
    left(90)
    pendown()

setup(1.0, 1.0)

def RotateRight():
    right(90)

def RotateLeft():
    left(90)

def Up():
    penup()
    goto(xcor(),ycor()+(letter_height+5))
    pendown()

def width1():
    width(1)

def width2():
    width(2)

def width3():
    width(3)

def width4():
    width(4)

def width5():
    width(5)

def width6():
    width(6)

def width7():
    width(7)

def width8():
    width(8)

def width9():
    width(9)

def width10():
    width(10)

def Blue():
    color("blue")

def Red():
    color("red")

def DarkGreen():
    color("dark green")

def Purple():
    color("purple")

def Pink():
    color("pink")

def Brown():
    color("brown")

def Orange():
    color("orange")

def Black():
    color("Black")

def OriginalColor():
    color(pen_color)

def getColor():
    Color = askcolor()
    color_name = Color[1]
    colormode(255)
    color(color_name)

move_turtle()
speed(0)
color(pen_color)
listen()
##onkey(Color, "F10")
onkey(NewLetterDimensions, "k")
onkey(width1, "1")
onkey(width2, "2")
onkey(width3, "3")
onkey(width4, "4")
onkey(width5, "5")
onkey(width6, "6")
onkey(width7, "7")
onkey(width8, "8")
onkey(width9, "9")
onkey(width10, "0")
onkey(Blue, "F1")
onkey(Red, "F2")
onkey(DarkGreen, "F3")
onkey(Purple, "F4")
onkey(Pink, "F5")
onkey(Brown, "F6")
onkey(Orange, "F7")
onkey(Black, "F8")
onkey(getColor, "F9")
onkey(OriginalColor, "F10")
onscreenclick(goto)
onscreenclick(skip)
onkey(clear, "space")
onkey(back, "BackSpace")
onkey(walk, "Tab")
onkey(Up, "Up")
onkey(draw_H, "h")
onkey(bye, "Escape")
onkey(draw_E, "e")
onkey(draw_L, "l")
onkey(draw_O, "o")
onkey(draw_W, "w")
onkey(draw_R, "r")
onkey(draw_D, "d")
onkey(draw_newline, "Return")

这里:

angle_height = (sqrt(letter_width**2 + (letter_height/2)**2))
a = (degrees(acos(letter_width/angle_height)))
b = (90-a)
R_angle = (90+b)

D_angle = (90+(degrees(acos(letter_width/angle_height))))
Second_D_angle = ((90 - (D_angle-90)) + (90-(degrees(acos(letter_width/angle_height)))))
D_space_angle = (degrees(atan(letter_width/(letter_height/2))))
space_angle = (180 - R_angle)

我遇到的问题是:

def NewLetterDimensions():
    def NewLetterHeight():
        global letter_height
        letter_height = (numinput("New Letter Height", "Please set the new letter height: ", minval = 10, maxval = 170))
    def NewLetterWidth():
        global letter_width
        letter_width = (numinput("New Letter Width", "Please set the new letter width: ", minval = 10, maxval = 170))
    NewLetterHeight()
    NewLetterWidth()
    penup()
    goto(xcor(), ycor() +letter_height)
    pendown()
    listen()

以上代码块允许用户在执行时更改颜色值,并由以下函数调用:

onkey(NewLetterDimensions, "k")

问题是,当 NewLetterDimensions() 函数中变量的值发生变化时,并非所有分配给该变量的位置都随该值变化!其实只有的地方这里没变:

angle_height = (sqrt(letter_width**2 + (letter_height/2)**2))
a = (degrees(acos(letter_width/angle_height)))
b = (90-a)
R_angle = (90+b)

D_angle = (90+(degrees(acos(letter_width/angle_height))))
Second_D_angle = ((90 - (D_angle-90)) + (90-(degrees(acos(letter_width/angle_height)))))
D_space_angle = (degrees(atan(letter_width/(letter_height/2))))
space_angle = (180 - R_angle)

当值改变时,"R",例如,画成这样:

R with the function

与其这样,不如这样:

R without the function

"D" 也是如此,因为如您所见,"D" 也使用由变量指定的角度。似乎分配给函数的所有其他值都发生了变化,而不是分配给变量的值发生了变化。为什么会发生这种情况,我将如何补救?非常感谢关于这个问题的任何帮助! :)

首先,from <module> import *会导致很多问题。例如,turtlemath 都定义了名为 degrees 的函数。我在编写下面的代码时遇到了一个错误,其中 Python 试图使用 turtle.degrees 而不是 math.degrees。最好不要使用 * 并在调用函数时使用模块名称,例如a = math.sin(math.pi/2)。它可以帮助您(和 Python!)了解每个对象的来源,因为 math.degrees(foo)turtle.degrees(foo) 明显不同。您也可以只导入您知道需要的东西,例如 from turtle import forward, left, penup

关于你的问题。这是如此随意使用全局变量的危险之一。使用您当前的方法,您 必须 全局更改 letter_widthletter_height,但根据它们计算的变量是另一回事。我要做的是让每个绘图函数采用宽度和高度参数,并在函数范围内进行数学计算。像

def draw_R(width, height):
    # This function will draw an R
    slant_height = math.sqrt(width**2 + (height/2)**2)
    slant_angle = math.degrees(math.acos(letter_width/slant_height))

    turtle.left(90)
    turtle.forward(height)
    turtle.right(90)
    turtle.forward(width)
    turtle.right(90)
    turtle.forward(height/2)
    turtle.right(90)
    turtle.forward(width)
    turtle.left(90+slant_angle)
    turtle.forward(slant_height)
    turtle.left(slant_angle)
    draw_space()

然后 onkey 绑定变为

onkey(lambda: draw_R(letter_width, letter_height), "r")

您必须使用 lambda,因为从技术上讲,回调不能接受参数。您还可以像这样简化 NewLetterDimensions

def NewLetterDimensions():
    global letter_height
    letter_height = (numinput("New Letter Height", "Please set the new letter height: ", minval = 10, maxval = 170))

    global letter_width
    letter_width = (numinput("New Letter Width", "Please set the new letter width: ", minval = 10, maxval = 170))

    penup()
    goto(xcor(), ycor() +letter_height)
    pendown()
    listen()

如果您像这样重新组织代码,那么您就可以消除很多 "Wait, what value does the variable have now?" 全局变量的混淆。