Question

I'm trying to use the Turtle module in Python to draw the American flag using separate functions, first I have draw_flag which calculates all the dimensions, and then draw_rectangle which actually draws the flag shape, then ill make draw_stars, etc, to draw the stars and lines.

But, I am having a bit of trouble understanding on how functions work..here is my code so far:

import turtle
import time
import random

def draw_rectangle(length, height):
    turtle.up()
    x = length
    y = height

    turtle.begin_fill()
    turtle.setpos(x,y)
    turtle.down()
    turtle.forward(418)
    turtle.right(90)
    turtle.forward(220)
    turtle.right(90)
    turtle.forward(418)
    turtle.right(90)
    turtle.forward(220)
    turtle.end_fill()

    turtle.sleep(2)
    turtle.bye

def draw_flag(A):
    height = int(A)
##    length = height*1.9
##    union_height = height*(7/13)
##    union_length = length*(2/5)
##    E = F = union_height/10
##    G = H = union_length/12
##    stripe_width = height/13
##    diameter_star = stripe_width*(4/5)
    length = height*1.9
    return

A = input("Please enter the height of the flag: ")

draw_rectangle(length, height)

I was hoping it would return by drawing a rectangle, but it keeps saying length is not defined, not sure where to place 'length' where it will recognize the variable.

I'm using Python 3, thanks.

Was it helpful?

Solution

Here's a good way to think about it. A function is a "black box" that takes in some number of values, called arguments, in a specific order and does something with them to produce some other value. When I say "black box," I mean that when you use the function, you don't have to care how it does what it does, you just give it some values and you get a value back.

Let's consider a very simple function that just subtracts the two numbers it's given: the first minus the second. In other words, we'll make a function that implements the rule "argument #1 - argument #2." Now, when you're writing the code for this function, you need some way to tell the computer when you want to use argument #1 and when you want to use argument #2. In some other programming languages, you have to do it by explicitly specifying the number of the argument you want to use (#1 or #2), but it's a lot easier to write code if you can give these values names. So Python, like most other languages, lets you refer to the arguments of a function using names of your choosing. For example, suppose you want argument #1 to go under the name x, and argument #2 to go under the name y. You could indicate that by writing this:

def subtract(x, y):

This would be followed by the code that constitutes the function. For the subtraction example, it would be

def subtract(x, y):
    return x - y

When the Python compiler encounters this, it translates the code into its internal representation of "calculate value #1 - value #2 and send that back to my caller." It then packs up that block of code and saves it under the name subtract (because that's what you told it you wanted to name the function).

Hopefully it makes sense that once this block of code finishes executing, it no longer makes any sense to refer to "argument #1" or "argument #2," because you can't have arguments without a function! So similarly, once the function has done its thing, the labels that you gave to the arguments, x and y, no longer have any meaning. The labels only exist for the duration of the function's code. This is called scoping: limiting labels to the part of the code where they mean something.

Because the labels x and y are locally scoped, as one might say, in a way it doesn't even matter what they are. For instance, if you had that definition of subtract in your code, you could arbitrarily decide to change them to first and second, and all you would have to change would be the code within that one function. You would just change the definition to

def subtract(first, second):
    return first - second

and that's it - your code is functionally exactly the same. Anywhere else in the program that x and y occur, they're referring to something other than the arguments of this function, so you don't have to change them when you rename the arguments.

What's happening in your case is that you tried to use the label length somewhere outside of the function it was defined for (namely, the function that you've stored as draw_rectangle). Python knows that you can't be referring to the argument of a function you're not in, so it expects you to have already defined length to mean something else. But you didn't. That's why you're getting an error. (Well, that one error, anyway)

OTHER TIPS

You have two problems. First, you define the function draw_flag but you don't ever call it.

However, if you did call it, it wouldn't work, because your function draw_flag doesn't really do anything. It just defines some variables inside itself and then throws them away when it ends. You should return the length and height with return length, height, then do length, height = draw_flag(A) and call draw_rectangle with those values. (Or you could do draw_rectangle(*draw_flag(A)).)

length, height = draw_flag(A)
draw_rectangle(length, height)

Functions don't magically communicate with one another. A function takes inputs and produces a return value. If you want to use that return value somewhere else, you need to call the function at the place where you want to use the value.

You are calling the function draw_rectangle, which expects two arguments - a length and a height. The length is being calculated by the draw_flag function; but you don't return the value.

You have a few ways of solving this. One is to simply call the draw_flag function with the user supplied height, save the return value, and then call draw_rectangle:

def draw_flag(A):
    height = int(A)
##    length = height*1.9
##    union_height = height*(7/13)
##    union_length = length*(2/5)
##    E = F = union_height/10
##    G = H = union_length/12
##    stripe_width = height/13
##    diameter_star = stripe_width*(4/5)
    return height*1.9

A = input("Please enter the height of the flag: ")
length = draw_flag(A)
draw_rectangle(length, int(A))

The other is to move your input to the draw_flag function, and then call the draw_rectangle function from inside the draw_flag function. If you do this, then the draw_flag function doesn't need any arguments at all:

def draw_flag():
    A = input("Please enter the height of the flag: ")
    height = int(A)
##    length = height*1.9
##    union_height = height*(7/13)
##    union_length = length*(2/5)
##    E = F = union_height/10
##    G = H = union_length/12
##    stripe_width = height/13
##    diameter_star = stripe_width*(4/5)
    draw_rectangle(height*1.9, height)

draw_flag()

I think you should also go through your Python book's section on variable scopes. It will help later on when you expect some variables to print but you get strange errors - especially if you are using functions.

Try the following

import turtle
import time
import random

def draw_rectangle(length, height):
   turtle.up()
   x = length
   y = height

   turtle.begin_fill()
   turtle.setpos(x,y)
   turtle.down()
   turtle.forward(418)
   turtle.right(90)
   turtle.forward(220)
   turtle.right(90)
   turtle.forward(418)
   turtle.right(90)
   turtle.forward(220)
   turtle.end_fill()

   turtle.sleep(2)
   turtle.bye

 def draw_flag(A):
   height = int(A)
   length = height*1.9
   draw_rectangle(length,height)
   return

A = input("Please enter the height of the flag: ")

draw_flag(A)

Okay, so to answer your more general question, functions in python accept arguments when you call them, these are passed by reference, which means that you end up with the same data inside the function as in the calling space. This is important for mutable types, because if they are changed inside the function, they are changed outside the function too. (str, int, float and tuple are not mutable, dict and list are). When a function returns, the value after the return token is passed back to the caller, so if you say a=input('input? '), the function input takes an argument for the prompt to display to the user, note this is passed in by reference, it is not a copy of the string. It returns the user generated input, which gets stored into a. You can return multiple values from a function, they are converted automatically to a tuple; if you have

def test():
    return 1,2
a,b = test()

You will get a=1 and b=2. Names used inside a function must be defined. They are first sought inside the function, then in any enclosing namespaces, finally in builtins. Variables defined in other functions cannot be used, because they are not in the local namespace nor any of its parents. To access the values of these names, you have to pass them in to the function, note that the names used inside the function don't have to match the names outside the function. Consider:

def fun1(a):
    return a * 2
def fun2():
    b = 5
    c = fun1(b)
    print c
fun2()

The value 5 is stored in memory under the name b, then passed by reference into fun1, this time under the name a, it is doubled and returned, (the return is also by reference), the return value is then stored under the name c, which is then printed.

return returns whatever you give it back to the caller. It does not automatically make the local variables inside the function available outside (these are local for a reason!). Note too that return without any arguments will return the special value None (so it's equivalent to return None).

So, if you want to return some values, use return height, length inside the function, and height, length = draw_flag(A) outside.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top