Module #4

In this module you will explore how to write your own custom functions in Python. Functions are often used as a technique to break up complicated problems into simple, reusable blocks of code.


Basic User Defined Functions

A function is an organized collection of statements within a program that can be called upon to perform a specific action. Since the beginning of the semester, we have been using a number of Python’s built-in functions, including the print, len, and range functions.

As you continue to write programs, they will inevitably become more and more complex. In order to help organize and make sense of such a large amount of code, programmers often organize their programs into smaller, more manageable chunks by writing their own functions. This lets us break down a program into several small functions, allowing us to focus on one isolated portion of a program at a time. Some benefits to using functions include:

  • Your code is easier to read: programs tend to look "cleaner" when broken down into smaller, more manageable tasks. for example:
     get_sales_figures()
     compute_tax()
     generate_output()
  • Your code is re-usable: once you write a function you can use it any number of times in your program without having to "copy and paste" the same blocks of code over and over again
  • Collaboration: with well-defined functions you can easily divide up the work on a large programming project among a group of programmers and then use those functions as part of a larger software system. In addition, functions can be shared between programs when the are placed inside of a "module"

Defining your own functions is easy in Python. To begin, you need to make up a name for your function. Functions follow the same naming rules that exist for variables (no spaces, can't start with a number, etc - see Module 1 for a full discussion on valid names for variables)

Defining functions requires the def keyword followed by the name of the function you wish to define. Next, you need to add two parenthesis after the name of the function and the "colon" character. From there you can indent any number of lines of code within your newly created function. Here’s an example function definition:

# this defines a function called "myfunction" 
def myfunction():
 	print ("Printed from inside a function")

Defining a function doesn't run the code inside of the function - it simply tells Python that you have created a function with a particular name. To actually use your function you need to call it, much like how you have to call a pre-written function like the print function before you can use it. Here's an example:

def myfunction():
	print ("Hello, world!")
    
##### main program #####  

# call the function that we just wrote
myfunction()

As you can see, functions must be defined before they can be used. The following code wouldn't work in Python because the function "myfunction" doesn't exist yet when it is called:

myfunction()

def myfunction():
	print ("Hello, world!")

In Python we generally place all of our functions at the beginning of our programs or in an external module.

Once a function has completed, Python will return back to the line directly after the initial function call. For example:

Sample Program: This program illustrates the flow of a program with multiple function calls:


When a function is called programmers commonly say that the “control” of the program has been transferred to the function. The function is responsible for the program's execution until it runs out of statements, at which time control is transferred back to the point in the program that initially "called" the function.

Sample Program: This program defines two functions - "top"and "side" - which are used to draw a rectangular shape using the asterix character.


Programming Challenge: Write a program that generates the following pattern. Use functions to break up the problem into reusable blocks of code. Refer to the previous programming challenge as necessary! Click the "Run" button to check your work, and click here to download the solution.

#####
#   #
 # #
  #
 # #
#   #
#####


Function Arguments & Variables

You can define variables inside functions just as you would in your main program.  However, variables that are defined inside of a function are considered local to that function, which means that they only exist within that function and are no longer available once the function has completed executing. We refer to these variables as local variables.

Code that is written outside of a function will not be able to access a local variable created inside of a function.  Here’s an example of how this works - the code below will result in an error because the main program is trying to access a local variable that was defined inside of a function:

# define a function that asks the user to enter a 
# number of items they wish to purchase
def purchase():
	numitems = int(input("How many items do you want to buy? "))
	print (numitems)
    
# call the purchase function
purchase() 

print (numitems) # error!  Variable numitems doesn’t exist in this scope!

Different functions can have their own local variables that use the same name.  Even though the variables share the same name, they are considered completely different variables that have no relationship to one another.

def square():
	num = 2
	print ("Square of", num, "is", num**2) 
def cube():
	num = 3
	print ("Cube of", num, "is", num**3)  
    
square()
cube()

Sometimes it is useful to not only call a function but also send it one or more pieces of data as "arguments." For example, when you call the print function you can send it an argument, like this:

print("hello!")

We can do the same thing with our own functions, like this:

my_awesome_function("hello!")

When passing arguments, you need to let your function know what kind of data it should expect to receive. You can do this by establishing a variable name in the function definition - these variable names go inside of the set of parenthesis after the function name.

# function that accepts one argument - a
def my_function(a):

Argument variables are automatically declared every time you call your function, and will assume the value of the argument passed to the function.  Here's an example function that accepts a value and stores it in the local variable "num":

Sample Program: This program demonstrates how you can call a function that is designed to accept an argument.


You can actually pass any number of arguments to a function. One way to do this is to pass in arguments "by position." Here’s an example:

# the average function expects 3 arguments
def average(num1, num2, num3): sum = num1+num2+num3 avg = sum / 3 print (avg) # call the function with 3 arguments average(100,90,92)

In the above example, the function argument variables (num1, num2 and num3) assume the values of the arguments passed into the function (100, 90, and 92)

When we pass an argument to a function in Python we are actually passing its "value" into the function, and not an actual variable.  We call this behavior "passing by value."  We are essentially creating two copies of the data that is being passed – one that stays in the main program and one that is passed as an argument into our function.  This behavior allows us to set up a "one way" communication mechanism – we can send data into a function as an argument, but the function cannot communicate back by updating or changing the argument variable because it is "local" to the function.

Sample Program: This program demonstrates how arguments allow you to "pass by value" - the argument variable is merely a "copy" of the data being sent into the function.


When you create a variable inside a function we say that the variable is "local" to that function.  This means that it can only be accessed by statements inside the function that created it.  When a variable is created outside all of your functions it is considered a "global variable" — global variables can be accessed by any statement in your program, including by statements in any function.  All of the variables we have been creating so far in class up until this module have been global variables.

Sample Program: This program demonstrates how a global variable can be viewed from within a function


However, if you want to be able to change a global variable inside of a function you must first tell Python that you wish to do this using the global keyword inside your function.  If you don’t use this keyword, Python will assume that you want to create a new local variable with the same variable name as the global variable.  Technically this isn’t an error, but it can get confusing!

Sample Program: This program demonstrates how a global variable can be viewed and changed from within a function


Programming Challenge: Write a function that converts a number from feet to inches (12 inches in a foot) and another function that converts feet to meters (0.3048 meters in a foot). Each function should accept a single argument and use that argument to calculate the conversion and print the result. Next, write a program that generates the following output - make sure to use your functions in your program! Click the "Run" button to check your work, and click here to download the solution.

0 ft:
... 0 inches
... 0 meters
1 ft:
... 12 inches
... 0.3048 meters
2 ft:
... 24 inches
... 0.6096 meters
3 ft:
... 36 inches
... 0.9144 meters
4 ft:
... 48 inches
... 1.2192 meters
5 ft:
... 60 inches
... 1.524 meters
6 ft:
... 72 inches
... 1.8288 meters
7 ft:
... 84 inches
... 2.1336 meters
8 ft:
... 96 inches
... 2.4384 meters
9 ft:
... 108 inches
... 2.7432 meters


Function Return Values

"Value returning functions" are functions that have the ability to send back, or return, information to the part of your program that called them. We've been using value returning functions since the beginning of the semester. For example, the "input" function is a value returning function - it "returns" a string when it is finished executing. We often capture that string and store it in a variable for later use in our program.

name = input("What is your name? ")

Syntactically value returning functions are almost identical to the types of functions we have been writing so far. The only difference is that you need to include a return statement in your function to tell Python that you intend to send back a value to whatever part of your program called the function. Here’s an example function that returns an integer to the caller:

def myfunction():     
    x = 5     
    return x  
    
somenumber = myfunction() 
print (somenumber)

When a function reaches a return statement it immediately ends the function and sends back the value attached to the statement. For example, this function will end early if you send it an even number as an argument because the return statement is reached prior to the second print statement:

Sample Program: The return statement will immediately cause a function to end and send back whatever value is attached to the return statement.


Note that in the above example we are storing the return value in a variable. This is functionally identical to when we store the string result that gets returned from the input function or the integer result that gets returned from the len function.

Sample Program: This program contains two functions - one function is used to ask the user for a price value and another function is used to apply a discount to a price value. Both functions are then used as part of a larger program.


In Python, functions can return more than one value. You can do this by separating the return values using a comma. Remember that if you return more than one value then your calling program must be expecting the same number of values. Here’s an example:

Sample Program: This program shows how a function can return multiple values in Python. Note that if you return multiple values from a function you also need to capture those values when calling the function. You can do this by separating the variables used to capture the return values using commas.


Programming Challenge: Write a function that rolls two dice. Your function should be designed to accept a single argument (an integer) and generate two die rolls between 1 and the number supplied. Your function should then return the two rolls in ascending order. Next, write a program that rolls 5 sets of dice with different sides. Here's a sample running of your program:

6 sided dice roll: 2 & 4
7 sided dice roll: 3 & 4
8 sided dice roll: 1 & 8
9 sided dice roll: 7 & 7
10 sided dice roll: 4 & 6

Click the "Run" button to check your work, and click here to download the solution.



Type Annotations for Functions

When creating a function, the numbers and types of the arguments that a function expects as well as the type it returns should be taken into consideration in the function's design. Together, the name, arguments and return type of a function is called the function signature. The name and parameters are in the function header, the first line in the function.

Let's create a function that determines the number of slices of pizza 🍕 that every person gets given:

  • a number of pies
  • the number of slices per pie
  • the number of people eating pizza
def slices_per_person(pies, slices_in_pie, people):
    total_slices: int = pies * slices_in_pie
    per_person: float = total_slices / people
    return per_person

Based on the function header, we can see that this function requires three arguments, pies, slices_in_pie, and people. However, we don't know what types those arguments should be, and what kind of value is returned. Your Python editor doesn't know this either, so it can't warn you about any potential type errors. You'd have to run this code (well, this is short enough where you don't have to, but... but it's clear that your editor can't tell you!) to figure out that there's a runtime exception.

n: float = slices_per_person('a lot', 8, 12)

Just like variables, we can add type annotations to functions. We can specify what type each parameter is as well as what type the function returns.

For parameters, use syntax similar to type hints for variables:

def f(param1: name_of_type1, param2: name_of_type2):

For return values, add an arrow (->) and the name of the type right before the colon:

def f() -> name_of_return_type:

Let's annotate our 🍕 function! Perhaps all of our arguments should be int (I mean, I guess, you could get a fractional pie, but receiving whole pies is not a bad assumption unless you're dealing with a hungry delivery person)... and the return value should be a float (have you ever tried to cut a slice in half? ... trickier than programming, but possible!):

def slices_per_person(pies: int, slices_in_pie: int, people: int) -> float:

Now our type checker can warn us about potential type errors like this, because it knows that the first argument should be an int

# now the type checker should catch this!
n: float = slices_per_person('a lot', 8, 2)

Lastly, if you decide that you don't want your function to return anything, you can use None as the return value:

def f() -> None:

⚠️ Note, again, that our online editor doesn't accept type annotations 😢, but please continue using type annotations for variables... and now, functions too!


Keyword Arguments, Variable Number of Parameters

Keyword Arguments

So far, we've created functions that accept positional arguments. That is, the order of the value passed in to the function call determines what the name of the parameter that the argument value is bound to. For our pizza function (with type annotations!)...

def slices_per_person(pies: int, slices_in_pie: int, people: int) -> float:
    total_slices: int = pies * slices_in_pie
    per_person: float = total_slices / people
    return per_person

Calling the function slices_per_person(1, 4, 2) binds 1 to pies, 4 to slices_in_pie, and 2 to people. Order matters when passing in positional arguments to a function call. Python allows another way to specify arguments to a function, and that's by keyword arguments (not all languages support this feature). You can think of keyword arguments as named arguments that you pass in to you function, where the names match the parameters. This renders order irrelevant! Let's see how it works. When calling a function, place the following within the parentheses:

  • parameter name
  • equals sign
  • argument value

For our pizza function, we could rewrite the function call as:

n: float = slices_per_person(pies=1, slices_in_pie=4, people=2)

Since order doesn't matter, we can even mix up the keyword arguments, placing the number of pies last:

m: float = slices_per_person(slices_in_pie=4, people=2, pies=1)

Sample Program: This example shows that a function can be called with named arguments instead of positional arguments. The function f prints out the name of the parameter and its value. In the sample below, we try changing the order of arguments in when the arguments are passed in as positional versus keywords (named).



Lastly, you can mix calling a function with keyword arguments and positional arguments... but positional arguments must go first:

f('a', 'b', c='C')

Keyword arguments seem nice, but why use them? It seems like more typing! Well, it is, and as we've seen from most of the built-in Python functions, keyword arguments aren't used when they're called. In fact, ⚠️ not all functions accept keyword arguments, but the ones that we've made ourselves so far do. Hm...well, what's a reason to use keyword arguments, then?

The most common use for keyword arguments are to remove ambiguity when calling a function. In functions with one or two arguments, it's usually easy to infer what the argument is supposed to be. However, beyond that, it gets a bit tricky. For example, in our pizza function, was people the first argument or the last?

We'll see another reason to use this syntax, but for a different language feature...

Default Values

Keyword arguments are closely related to default values; they have very similar syntax. In fact, keyword arguments are often used to describe both default values and named arguments passed in to function calls. For our the purposes of this module, we'll differentiate the two by saying that keyword arguments are used when executing a function, and default values are used when defining a function and specifying a default value for one or more parameters.

When you define a function, you can use the same name=value to set a default value for the parameter with name, name. That leaves that argument optional! These parameters with default values can only be defined after positional parameters:

def f(a: str, b: str , c: str='c', d: str='d') -> None:

The function above can now be called with just 2 arguments:

f('a', 'b')

⚠️ AVOID USING MUTABLE OBJECTS (like lists and dictionaries) as default values. We may not have covered those data types yet, but we'll note it again once we do.

For our pizza function, we can make the number of slices in a pie 8 by default by moving slices_in_pie to the end of the parameters list and using = after the name and annotation to assign it a default value. We can call the function with our without the last argument (if we include it, it will override the default value):

# slices_in_pie: int=8 is moved to the end of the function header
def slices_per_person(pies: int,  people: int, slices_in_pie: int=8) -> float:

Use the code runner below to see the different ways that our new function can be called (note that type annotations are left out to allow the code to be run online).

Sample Program: One of the parameters in this function is given a default value. That parameter is now optional. Note the different ways that this function could be called (with and without the optional parameter).



Programming Challenge: Create a function called my_pow. It should have two arguments: a base and the exponent (both numbers). It should return the base raised to the exponent. For example, my_pow(3, 4) should return 81.

The second argument can be left out. If so, the exponent will be 0. Consequently, calling my_pow(10) should return 1.

Print out the result of calling the function twice. Use the following arguments for the function calls:

  1. 3
  2. 3, 2

The resulting output should look like this:

1
9

Click the "Run" button below to test your program. You can download the solution to this problem by clicking here.



Variable Number of Parameters

Finally, we can create functions that accept any number of arguments. In the function header, specify a single parameter name, prefixed with a * (asterisk):

def f(*args) -> int:
    return len(args)

The parameter name will be available in the body of the function as an iterable object (a value that you can loop over - we'll learn more about the exact type of this value in a later module):

  • the first argument will be the first element looped over, the second is the next element in the loop, etc.
  • the number of arguments can be determined by calling len on the parameter name

Sample Program: This demonstrates that a function can be defined to accept an arbitrary number of parameters



Programming Challenge: Create a function called product. It should take a variable number of arguments. Each argument will be used as a factor in a product and the return value will be the product of all arguments multiplied together. For example, product(2, 3, 4) should return 24. If there's only one argument, then return the same number. Type annotations can be left out of your definition. Additionally, no defensive programming is necessary to ensure that all arguments are numeric.

Use this new function to print out the product of the following sets of numbers:

  1. 2, 3, 4
  2. -10, 10, 5, 5
  3. 100

Prior to printing out each product, print out some informational text and the factors (separated by *): "The product of 2 * 3 * 4 is 24"

⚠️ The function will only return the product... the rest of the text should just be combined with the function's return value to generate the expected output.

The product of 2 * 3 * 4 is 24
The product of -10 * 10 * 5 * 5 is -2500
The product of 100 is 100

Click the "Run" button below to test your program. You can download the solution to this problem by clicking here.




Function Scope

Scope is the region within a program where a variable is accessible. We know two scopes in Python:

  • global - variables declared in the global scope are available everywhere
  • local - variables declared locally:
    • are only available in the code block they are defined in -- specifically, within the function that the variable was created
    • ...and cannot be accessed outside of the function they were created in

Just a reminder, global variables can be read from anywhere after they've been declared - for example, within a function:

Sample Program: A global variable can be accessed from within a function: in this case, the function f has access to x even though x is not defined in the function.



While using global variables is convenient, it's best to minimize the number of global variables in your program:

  • multiple global variables "pollute" your namespace, the pool of possible variable names you can choose from, increasing the chance of variable name collisions (undesirable as you may inadvertently overwrite variable values)
  • having functions depend on global variables means those functions aren't reusable unless those specific global variables are declared!

So... the only way we can create "new" scopes (at least with what we know) in Python is by creating functions (which give us the possibility of hiding variables by making them local variables within a function). We can use this to our advantage. One reason for creating a main function to house the entirety of your program is so that all variables are isolated within a single function rather than having them all available globally; main creates a new scope. ⚠️ Again, the only way (that we know of) to create a new scope in Python is by creating functions. This is different from other languages, like Java, which have block level scoping. Let's take a look at some examples:

Sample Program: We create a main function that produces a new scope (a scope local to the function). Within that scope, the variable untouchable is accessible, but outside of it, it isn't accessible. We get a NameError in this case!



Sample Program: Note that the variable s is modified within the function f, but it has no affect on the global variable, s. The local variable within f is isolated!



Using scopes to isolate variables and prevent them from leaking into the global scope is a common technique for reducing name collisions and related bugs.

A function can be defined within another function. If this is the case, then the nested inner functions have access to all of the variables defined in the enclosing outer function.

Sample Program: This program shows that nested functions have access to the variables created by the outer function that encloses them. The body of g has access to the variable s declared in the enclosing outer function, f.



When Python encounters a variable, it travels up the scope chain to determine what value is bound to the variable (in Python, this is called name resolution). From the Python documentation:

"When a name is used in a code block, it is resolved using the nearest enclosing scope. The set of all such scopes visible to a code block is called the block’s environment."

So, in short, Python looks for the value of a variable in the following places (in order):

  1. local variables (if within function)
  2. variables local to the enclosing function (if enclosing function is present)
  3. global variables
  4. built-in names that are automatically bound to values, like print

This gives us all of the names available within a scope (this set of available variable names is called the environment).

A mnemonic device to remember variable name resolution order is: LEGB:

  • L ocal
  • E nclosing
  • G lobal
  • B uilt in

The following example demonstrates name resolution order:

Sample Program: This program shows how Python determines the value of a variable.

Can you guess what the output of the program below will be? Here's how to figure it out:

  • In the innermost function, g, the variable name, mystery, is referenced. It is defined locally, and consequently, that value is used rather than the other values bound to mystery in the enclosing function and globally.
  • Within g, the variable name, enclosing_var, is referenced. It is not present locally, so it uses the variable defined in the enclosing function


If variable name binding occurs anywhere in a scope, any reference to that variable name will be treated as if it were an existing local variable. This is the case even if the name actually exists locally. This is best demonstrated via example code:

Sample Program: It looks like x is global, and typically global variables can be accessed from anywhere, even within function. However, based on the information above, what do you think the actual output of this program will be?



This results in a name error 😯! What‽ Because there is assignment somewhere within the body of the function, Python treats every occurrence of x local to puzzling such that it is a local variable. Consequently, the first print(x) tries to find x locally, which isn't set until the next line. The result in an error (UnboundLocalError)

A similar thing happens in this example:

x = 1
def increment():
    x += 1 # NameError too!
increment()

This also results in UnboundLocalError because there's assignment in the += operator. Consequently, x is treated as local, so when 1 is added to it, a runtime error occurs. This behavior is a bit unexpected, and Python calls it out in its FAQ.


Creating Modules

Modules Recap

A module is just a file with some Python definitions and statements in it. Usually (hopefully!) the code provides reusable implementations (definitions and statements) of solutions to common programming tasks -- tasks like handling .csv files or downloading data from the web . Modules can be brought in to other Python programs so that the module's defined functionality can be used. An example of a module that we've used before is the random module. It exists as a file somewhere on your file system (random.py), and it provides definitions for functions, like randint, random and randrange.

If you were to open random.py, you'd see that it's just a regular text file containing Python code. This implies, then, that every Python file you write can also be used as a module 😮! YES, THAT'S RIGHT!

Creating Modules

You can create your own module simply by creating a Python file! That's it!

The definitions (actually, all the code) in a module can be brought in to another file by using the import statement. However, the import statement drops the .py extension from the file that it's bringing in (if you'd like to use some_module.py, use import some_module).

Import Behavior

When a module is imported using the import some_module syntax:

  1. You have access to the definitions in the module through the name of the module that you imported (again, without the .py extension)
  2. All of the code in the module is executed where the import occurs

Here's an example module, good_doggo.py:

# in good_doggo.py
breed = 'schnoodle'

def talk():
    print('bork!!!')

print('heckin modules!')

Another file, called my_program.py is in the same directory as good_doggo.py, and it has the following code:

# in my_program.py
print('1')
import good_doggo
print('2')

Running my_program.py brings in the code from good_doggo.py and executes it at the point of import. Although there are only two print statements in my_program.py, running it prints out 3 lines:

1
heckin modules
2

The second line actually comes from the fact that the imported module, good_doggo.py has a print statement in it.

Accessing Module Definitions and Scope

Additionally, the definitions in good_doggo.py are available by prefixing variable and function names with the name of the module imported:

# modified my_program.py
import good_doggo
good_doggo.talk()

The talk function can be used by prefixing it with the module name, good_doggo. The result of running my_program.py with the code above is now:

heckin modules
bork!!!

If using the import some_module syntax, the code in the module follows the regular rules for scope in the module file itself: if there's a global variable in the module, it can be used anywhere in that module... locals can only be used within the function they were defined it. However, as we saw above, to use the names (global variables, top-level functions) defined in a module in another program, the importing file must use the module name as a prefix. There are ways around this, which we'll see later on.

Module Location

For now, it's ok to think of using import to bring in code from files that are in the same directory as your program... or for modules that come with Python, like random, math, or sys.

What does this mean? Well, if you're using an editor that stores all files in a project in the same folder (like PyCharm), then you can go about writing your code normally, but now you have the super power 💪 of using import to reuse files that are in the same project. Alternatively, you can just make sure the files that you're importing are in the same directory as the program that you're using import in.

You can configure Python to look for modules in specific directories by using a special environment variable called PYTHON_PATH. An environment variable is not a python variable, but, instead, it's a configuration or setting used when running your Python program (this can be done different ways depending on how your run your Python program and what operating system you use). With that said, we will stick with keeping modules in the directory that we're working in.

Why Create Modules?

Now that we know the mechanics of creating modules (spoiler 🙈, any Python file you create can be a module; you just import it!), let's figure out why you would want to go through the trouble of stashing code in one file and using it in another... rather than just writing all of your code in a single file.

Making our own modules is useful because:

  • As our programs get longer, it may be nice to group together related functions (and other definitions) in their own files (that is modules), and bring them in to our main program to organize our work
  • Additionally, if we want to reuse certain functions, just move functions to a module and import them in any file you like (reuse FTW 🏁)

What's in a __name__?

Within any Python file, there's a special variable that's automatically created called __name__.

Sample Program: Notice that __name__ is not defined, but we can print it out!



As you can see from the sample above, the variable, __name__ is bound to the string, "__main__", automatically! However, this binding changes if you import the Python file rather than running it directly.

If used as a module, the special variable __name__ will contain the name of the module as a string.

For example given the two files my_module.py and my_program.py, the __name__ variable in my_module.py will be bound to the string, "my_module", when the my_module.py is used by importing:

# in my_module.py
print(__name__)
# in my_program.py
import my_module

Running my_program.py produces the following output:

my_module

This special variable, __name__, can be used when you want to test your module implementation with print statements within your module's code, but you don't want those print statements executed when your module is imported:

# in my_module.py
foo = 'bar'
if __name__ == '__main__':
    print('this will not be printed if the module is imported')
    print('...but it will be printed if this file is run directly')
# my_program.py
import some_module
print(some_module.foo)

Running my_program.py only prints out bar. The print statements in some_module are not executed because of the if statement. ⚠️ However, if my_module.py is run directly, then the variable, __name__, will be set to the string "__main__"... so the print statements will run.

Other Ways to Import

So far, we've imported modules using this syntax:

import some_module

When we use import in this way, all references to definitions in the module from the importing program must prefix those references with the module name. There are other ways to import modules, though...

Aliasing
import some_module as some_alias 
  • in this case, some_alias can be used as prefix instead of the module name
  • this is handy when a module name is too long to use repeatedly
  • example usage:
    import random as rnd`
    roll = rnd.randint(1, 6)
Choosing What to Import
from some_module import some_name
  • this method of importing can be used to bring in a specific name (function or variable) from a module
  • consequently, to use the variable or function, a prefix is not needed!
  • use this to:
    • avoid having to prefix your module functions / names with the name of the module
    • narrow down which part(s) of the module you're using
  • example usage:
    from random import randint
    roll = randint(1, 6)

There's one last way of importing that you should not use, but you may encounter in other code: from some_module import *. This imports all definitions from module in such a way that a prefix is not needed to use them... but, because it brings in all definitions, this may overwrite variables that you've already declared 🙅‍♀️.


Installing Modules

So far, we've checked out modules that come bundled with Python (like math, sys, etc.). We've also created our own modules by writing Python files that we import into another program.

Now let's take a look at using modules built by the Python community... that is, useful modules that someone else built. These are modules provide functionality that doesn't come with Python or that improve upon a built-in Python module. These 3rd party modules are available through the Python Package Index (https://pypi.org).

They can be downloaded and installed using tools that come with Python or with your IDE / editor. The video above demonstrates using PyCharm to install two popular modules:

  1. Pillow (PIL) - an image processing library
  2. matplotlib - a graphic library
The code used in the video is below. The samples are meant only to demonstrate the use of 3rd party modules / packages, so there will definitely be syntax and concepts that are unfamiliar.
Image Processing Example
from PIL import Image
# if you want to try this out...
# download the image to your project folder
# and replace the string passed to open
# with the name of the image in quotes
img = Image.open('/tmp/demo/wallaby.jpg')
data = img.getdata()
img.putdata([(d[0], 0, 0) for d in data])
img.show()
Graphing Example
import matplotlib.pyplot as plt
import numpy as np
feels = ['thumbs up', 'sad face', 'potato']
votes = [10, 2, 12]
plt.bar(np.arange(len(feels)), votes)
plt.xticks(np.arange(len(feels)), feels)
plt.ylim(0, 14)
plt.ylabel('Votes')
plt.xlabel('Feels')
plt.title('How U Feel Abt This Graph?')
plt.show()

Quiz

Now that you've completed this module, please visit our NYU Classes site and take the corresponding quiz for this module. These quizzes are worth 5% of your total grade and are a great way to test your Python skills! You may also use the following scratch space to test out any code you want.

Feedback

Tell us what you thought about this module (it's anonymous).
How helpful did you find this module on a scale of 1-5:
Very unhappy face
Unhappy face
Neutral face
Happy face
Very happy face
Which resource(s) in this module did you find the most helpful (check all that apply):

Copyright 2014-2018