It's probably been a while since you read about using functions. Read about it again if you need to.
Have a look at this code:
print("************") print("Hello World!") print("************") print("*************") print("Enter a word:") print("*************") word=input() ifword=='python': print("*******************") print("You entered Python!") print("*******************") else: print("**************************") print("You didn't enter Python :(") print("**************************")
Then compare it to this code:
print_box("Hello World!") print_box("Enter a word:") word=input() ifword=='python': print_box("You entered Python!") else: print_box("You didn't enter Python :(")
In this tutorial we'll learn to define a print_box
function that prints text in a box. We can write the code for printing the box once, and then use it multiple times anywhere in the program.
Dividing a long program into simple functions also makes the code easier to work with. If there's a problem with the code we can test the functions one by one and find the problem easily.
The pass
keyword does nothing.
>>>pass>>>
Let's use it to define a function that does nothing.
>>>defdo_nothing(): ... pass ... >>>do_nothing<functiondo_nothingat0x7f56b74e9598>>>>
Seems to be working so far, we have a function. It's just a value that is assigned to a variable called do_nothing
. You can ignore the 0xblablabla
stuff for now.
The pass
is needed here because without it, Python doesn't know when the function ends and it gives us a syntax error. We don't need the pass
when our functions contain something else.
Let's see what happens if we call our function.
>>>do_nothing() >>>
There we go. It did nothing at all.
Maybe we could just do something in the function instead?
>>>defprint_hi(): ... print("Hi!") ... >>>print_hi() Hi! >>>
It's working. How about printing a variable in the function?
>>>defprint_message(): ... print(message) ... >>>message="Hello World!">>>print_message() HelloWorld! >>>
Again, it works. How about setting a variable in the function?
>>>defget_username(): ... username=input("Username: ") ... >>>get_username() Username: me>>>usernameTraceback (mostrecentcalllast): File"<stdin>", line1, in<module>NameError: name'username'isnotdefined>>>
That was weird! Why didn't that work?
So far we have used nothing but global variables. They are called globals because the same variables are available anywhere in our program, even in functions.
>>>a=1>>>b="hi">>>c="hello">>>defprint_abc(): ... print(a, b, c) ... >>>print_abc() 1hihello>>>
But there are also local variables. They exist only inside functions, and they are deleted when the function exits.
>>>defthingy(): ... d="hello again, i'm a local variable" ... print('inside thingy:', d) ... >>>thingy() insidethingy: helloagain, i'malocalvariable>>>dTraceback (mostrecentcalllast): File"<stdin>", line1, in<module>NameError: name'd'isnotdefined>>>
Let's draw a diagram of these variables:
However, modifying a global variable in-place from a function is easy.
>>>stuff= ['global stuff'] >>>defadd_stuff(): ... stuff.append('local stuff') ... >>>add_stuff() >>>stuff ['global stuff', 'local stuff'] >>>
This only works for changing in-place, we cannot assign a new value to the variable.
>>>defset_stuff_to_something_new(): ... stuff= ['more local stuff'] ... >>>set_stuff_to_something_new() >>>stuff ['global stuff', 'local stuff'] >>>
Note: This section has nothing to do with the input
function that is used like word = input("enter something: ")
.
So far our functions seem to be really isolated from the rest of our code, and it sucks! But they really are not as isolated as you might think they are.
Let's think about what the print function does. It takes an argument and prints it. Maybe a custom function could also take an argument?
>>>defprint_twice(message): ... print(message) ... print(message) ... >>>
Here message
is an argument. When we call the function we'll get a local variable called message that will point to whatever we passed to print_twice
.
This function can be called in two ways:
Using a positional argument.
This is the recommended way for functions that take only one or two arguments. I would do this in my code.
>>>print_twice("hi") hihi>>>
When the function was running it had a local
message
variable that pointed to"hi"
. The function printed it twice.Positional arguments are great for simple things, but if our function takes many positional arguments it may be hard to tell which argument is which.
Using a keyword argument:
>>>print_twice(message="hi") hihi>>>
The name "keyword argument" is a little bit confusing because keyword arguments don't actually have anything to do with keywords (
if
,else
etc). Keyword arguments are just a way to give names for our arguments.Keyword arguments are great when our function needs to take many arguments, because each argument has a name and it's easy to see which argument is which.
Also note that there are no spaces around the
=
sign. This is just a small style detail that Python programmers like to do becausemessage = "hi"
andsome_function(message="hi")
do two completely different things.
Now it's time to solve our box printing problem:
defprint_box(message): print('*'*len(message)) print(message) print('*'*len(message))
What if we want to print different characters instead of always printing stars?
We could change our print_box
function to take two arguments:
defprint_box(message, character): print(character*len(message)) print(message) print(character*len(message))
Then we could change our code to always call print_box
with a star as the second argument:
print_box("Hello World", "*") ...
But we don't need to change our existing code. We can make the second argument optional by giving it a default value.
defprint_box(message, character='*'): print(character*len(message)) print(message) print(character*len(message))
We can print a row of stars using the function without specifying a different character in two ways:
Using a positional argument.
print_box("Hello World!")
Using a keyword argument.
print_box(message="Hello World!")
Or we can give it a different character in a few different ways if we need to:
Using two positional arguments.
print_box("Enter a word:", "?")
Using two keyword arguments.
print_box(message="Enter a word:", character="?") print_box(character="?", message="Enter a word:")
Using one positional argument and one keyword argument.
I would probably do this. If an argument has a default value, I like to use a keyword argument to change it if needed.
print_box("Enter a word:", character="?")
However, this doesn't work:
print_box(character="?", "Enter a word:")
The problem is that we have a keyword argument before a positional argument. Python doesn't allow this. We don't need to worry about this, because if we accidentally call a function like this we will get an error message.
The built-in input function returns a value. Can our function return a value too?
>>>deftimes_two(thing): ... returnthing*2 ... >>>times_two(3) 6>>>times_two(5) 10>>>
Yes, it can. Now typing times_two(3)
to the prompt does the same thing as typing 6
to the prompt.
We can call the times_two
function and use the result however we want, just like we can use built-in functions:
>>>times_two(2) +times_two(3) # calculate 4 + 610>>>print('2 * 5 is', times_two(5)) 2*5is10>>>
Note that returning from a function ends it immediately.
>>>defreturn_before_print(): ... returnNone ... print("This never gets printed.") ... >>>return_before_print() >>>
If we don't have any return statements or we have a return statement that doesn't specify what to return, our function will return None.
>>>defreturn_none_1(): ... pass ... >>>defreturn_none_2(): ... return ... >>>print(return_none_1()) None>>>print(return_none_2()) None>>>
There are two ways to output information from functions. They can print something or they can return something. So, should we print or return?
Most of the time returning makes functions much easier to use. Think about the input()
function. It asks the user to enter something, and then the user enters something and that value is returned. If the input function would print the value instead of returning it, things like name = input("Name: ")
wouldn't work and assigning the result to a variable would be much more difficult. Printing things is fine when we know that we'll only need to print the result and we'll never need to assign it to a variable.
If our function returns a value we can always print it, like this:
>>>defreturn_hi(): ... return"hi" ... >>>print(return_hi()) hi>>>
Functions are easy to understand, but you need to pay attention to how you're calling them. Note that some_function
and some_function()
do two completely different things.
>>>defsay_hi(): ... print("howdy hi") ... >>>say_hi# just checking what it is, doesn't run anything<functionsay_hiat0x7f997d2a8510>>>>say_hi() # this runs ithowdyhi>>>
Typing say_hi
just gives us the value of the say_hi
variable, which is the function we defined. But say_hi()
calls that function, so it runs and gives us a return value. The return value is None so the >>>
prompt doesn't show it.
But we know that the print function shows None, so what happens if we wrap the whole thing in print()
?
>>>print(say_hi) # prints the function, just like plain say_hi<functionsay_hiat0x7fd913f58488>>>>print(say_hi()) # runs the function and then prints the return valuehowdyhiNone>>>
The print(say_hi())
thing looks a bit weird at first, but it's easy to understand. There's a print inside say_hi
and there's also the print we just wrote, so two things are printed. Python first ran say_hi()
, and it returned None so Python did print(None)
. Adding an extra print()
around a function call is actually a common mistake, and I have helped many people with this problem.
Ask yes/no questions.
defask_yes_no(prompt): whileTrue: answer=input(prompt+' (y or n) ') ifanswer=='y'oranswer=='Y': returnTrue# returning ends the functionifanswer=='n'oranswer=='N': returnFalseprint("Answer 'y' or 'n'.") ifask_yes_no("Do you like ice cream?"): print("You like ice cream!") else: print("You don't like ice cream.")
Ask questions with multiple answers.
defask_until_correct(prompt, correct_options, error_message="I don't know what you meant."): whileTrue: answer=input(prompt+' ') ifanswerincorrect_options: returnanswerprint(error_message) colors= ['red', 'yellow', 'blue', 'green', 'orange', 'pink', 'black', 'gray', 'white', 'brown'] choice=ask_until_correct("What's your favorite color?", colors, error_message="I don't know that color.") print(f"Your favorite color is {choice}!")
- Functions are a way to write code once, and then use that same code in multiple places.
- Variables inside functions are locals, and variables outside functions are globals. Functions can access all variables, but by default, they can only create and change the value of local variables.
- Functions can take arguments and they can behave differently depending on what arguments they get. Arguments are just local variables.
- Functions can also return one value, like the built-in input function does. Returning also ends the function immediately.
- Return a value instead of printing it if you need to do something with it after calling the function.
- Remember that
thing
,thing()
,print(thing)
andprint(thing())
do different things.
There are many things to learn about functions, and I don't expect you to learn everything at once. However, there are also many free exercises about defining functions you can do.
What's wrong with this code?
defask_name(): name=input("Enter your name: ") ask_name() print("Your name is", name)
How about this code?
defget_greeting(): return"Hello World!"print(get_greeting)
Why does this print None after greeting the world?
defgreet(target): print("Hello", target) print(greet("World"))
Find more exercises about defining functions online.
Answers for the first, second and third exercise are here.
If you have trouble with this tutorial, please tell me about it and I'll make this tutorial better, or ask for help online. If you like this tutorial, please give it a star.
You may use this tutorial freely at your own risk. See LICENSE.