(U)Unclassified

Functions

Functions Overview

  • Function Scope
  • Parameters and Arguments
    • Commandline Arguments
    • Returning
    • Pass By Reference
  • Lambda Functions
  • List Comprehension
  • Closures
  • Iterators and Generators

Objectives

Functions Objectives

Scope

  • The Scope determines the visiblity of variables in your program

LEGB Rule

  • In Python we use the LEGB Rule:

Local

  • Refers to variables defined within the function
							
								def sales_tax(amount):
									rate = 0.0625  # Local Variable
									tax_total = amount * rate # Rate can be seen here
									total = tax_total + amount
									print(total)

								# Call function and pass parameter
								sales_tax(200)  # Rate cannot be seen here									 
							
						

Enclosing-Function Global

  • Refers to variables defined within local scope of functions wrapping other functions
							
								def program():
									amount = 200 # Enclosing-Function Global variable
									def sales_tax(amount):
										rate = 0.0625
										tax_total = amount * rate # Amount can be seen here
										total = tax_total + amount
										print(total)

									sales_tax(200) # Amount could be seen here
									
								program() # Amount could not be seen here
							
						

Global/Module

  • Variables defined at the top level of files and modules
							
								amount = 200 #Global Variable

								def sales_tax(amount):
									rate = 0.0625  # Local Variable
									tax_total = amount * rate # Rate can be seen here
									total = tax_total + amount
									print(total)

								# Did not pass parameter
								sales_tax(200)
							
						

Built-In

  • Loaded into scope when interpreter starts
  • For Example:
							
								hash()
								min()
								dict()
								print()
							
						

Modifying Global Variables

We can use the global keyword to grant access to global variables

Modifying Global Variables Example

							
								a = 1

								# Uses global because there is no local 'a'
								def f():
									print('Inside f() : ', a)

								# Uses local variable a
								def g():    
									a = 2
									print('Inside g() : ', a)

								# Uses global keyword to grant access to global a, allowing modification
								def h():    
									global a
									a = 3
									print('Inside h() : ',a)

								# Global scope
								print('global : ', a)
								f()
								print('global : ', a)
								g()
								print('global : ', a)
								h()
								print('global : ', a)
							
						

Modifying Global Variables Output

							
								global :  1
								Inside f() :  1
								global :  1
								Inside g() :  2
								global :  1
								Inside h() :  3
								global :  3
							
						

User Functions

  • Python functions are blocks of reusable code
  • Functions are meant to split up the code into functionally organized reusable code
  • In Python, you do not have to return a value

Defining a Function

							
								def function_name(parameters):
									x = 0 # What we want to return

									return x # What we return
							
						

Function with a return value

							
								def name_upper(name):
									name = name*2
									return name # Return Value
								
								print(name_upper('Cao')) # Function call
							
						

Function without a return value

							
								def name_upper(name):
									# Your Code
									print(name)
							
						

Calling a Function

  • Call the function name
  • Pass in any needed argument
  • If the function returns a value, direct the return value to a variable
							
								# Lets print a name
								print_name('SrA. Snuffy')
							
						

Function Example

							
								def divisible_by(num, amount): # Function Definition		
									i = 1.0
									while (num / i >= 1 and amount > 0):
										if num % i == 0:
											print("{} divided by {} equals: {}".format(num, i, num / i))
											amount -= 1
										i += 1

								divisible_by(900, 10) # Function Call
							
						

User Functions (Labs)

Parameters and Arguments

  • Parameters are defined within the parentheses
  • They are undefined variables that you want to use within the function
  • Arguments are defined variables that you pass on the function call.

Parameter and Argument Example

							
								def sales_tax(amount): # function and parameter 'amount'
									rate = 0.0625
									tax_total = amount * rate
									total = tax_total + amount
									print(total)

								sales_tax(200) # Function call and argument 200
							
						

Default Parameters

							
								def divisible_by(num, amount = 5):
									i = 1.0
									while (num / i >= 1 and amount > 0):
										if num % i == 0:
											print("{} divided by {} equals: {}".format(num, i, num / i))
											amount -= 1
										i += 1
								divisible_by(900, 10)
							
						
							
								# Checks all numbers that can be divided into num... up until amount has been reached or we reach divide by self
								def divisible_by(num, amount=None):
									if amount is None:
										amount = 5

									i = 1.0
									while (num / i >= 1 and amount > 0):
										if num % i == 0:
											print("{} divided by {} equals: {}".format(num, i, num / i))
											amount -= 1
										i += 1
								divisible_by(900)
							
						

Copies vs. References

  • Objects are never copied into functions they are referenced

Example of Modification

							
								x = [1,2,3,4] # here we create a global list

								def test(x):
									x[1] = 20           # here we are modifying the mutable object via indexing
									x.append(50)        # here we are modifying the mutable object via method

								test(x)

								print(x)

								# output: 1,20,3,4,50
							
						

Example of Name Binding

							
								x = [1,2,3,4] # here we create a global list

								def test(x):
									x = [1,2,3,4,5]
									x.append(200)

								test(x)

								print(x)

								# output: 1,2,3,4
							
						

Args and Kwargs

  • *args are used to pass a non-keyworded, variable-length argument list.
  • **kwargs is used to pass a keyworded, variable-length argument list.
  • A keyword argument is where you provide a name to the variable as you pass it into the function.
  • kwargs are placed in dictionaries.

Args and Kwargs Example

							
								def my_func1(*args):
									for arg in args:
										print('arg: ', arg)
										print(type(args))
								def my_func2(**kwargs):
									for key, value in kwargs.items():
										print(key, value)
								my_func1('two', 3, 'four', 5)
								my_func2(a = 12, b = 'abc')
							
						

Command-Line Arguments

Arguments can also be passed through the command line or terminal.

Old Way Example

							
								import sys

								args = str(sys.argv)
								print(sys.argv[0]) # The name of the program is always argv[0]
								for i in range(len(sys.argv)):
									print 'args[%d]: %s' % (i, sys.argv[i])

								# Input Example: python2 test.py hello world "Hello World"
								# What is the output?
							
						

New Way Example

							
								import argparse

								parser = argparse.ArgumentParser(description='This is a demo')
								parser.add_argument('-i','--input',help='Input arg', required=True)
								args = parser.parse_args()

								print(args.input)

								# Input Example: python2 test.py -i test
							
						

Returning

  • With functions, you have the choice to return a variable
  • This is done so that the function becomes it's own local scope

Returning Example

							
								def create_initials(first_name, last_name):
									initials = first_name[0].upper() + last_name[0].upper()
									return initials

								initials = create_initials("jack", "black")
								print(initials)
							
						

Pass by reference

  • Pass by Object Reference means that objects passed to the functions are referenced
  • Python does this by default
							
								#Define the function
								def append_one(a):
									a.append(1)

								# Declare and set a variable
								a = [0]
								# Pass that variable by reference to the function append_one()
								append_one(a)
								print(a)

								# Since the function acted on a mutable variable... the contents of the object were changed.
								[0, 1]
							
						

Arguments and parameters (Labs)

Lambda Functions

  • Lambdas, are anonymous functions - functions without a name.
  • Lambda functions are passed as arguments to higher-order functions

Lambda Features

  • Lambda forms can take any number of arguments
  • Return only one value in the form of an expression
  • They cannot contain commands or multiple expressions
  • It cannot be a direct call to print because lambda requires an expression
  • Lambda functions have their own namespace

Lambda Function Example

							
								my_list = range(26)

								print(my_list)
								print(filter(lambda x: x % 2 == 0, my_list))
							
						
							
								lambda - the keyword to create a lambda
								x - the parameter. Multiple parameters ex: lambda x,y,z:
								x % 2 == 0: the execution code
								my_list: the argument. Multiple args ex: lambda x,y,z: code, input1, input2, key

								Multiple arg/param lambda: 
								lambda x,y,z: (x + y) - z, input1, input2, key
							
						

Lambda Breakdown

							
								#Define a regular function
								def reg_function(x):
									return x**2

								# Make it one line
								def reg_function(x): return x**2

								# Turn it into a lambda
								new_stuff = lambda x: x**2
							
						

Lambda Common uses

								
									# Map applies a function to all the items in an input_list. 
									# That function can be a lambda.
									map()

									# Filter creates a list of elements for which a function 
									# returns true.
									filter()
									
									# Reduce accepts a function and a sequence and returns a 
									# single calculated value.
									reduce()
								
							

Labs

Lab 4a

List Comprehension

  • Python supports something called "list comprehension", which allows us to write minimal, easy and readable lists
  • This way you can put everything in a one liner

Normal List

							
								a_list = [1,2,3,4,5]

								def square_list(a_list):
									a = []
									for item in a_list:
										a.append(item*item)
									return a

								print(square_list(a_list))

								# Output
								[1, 4, 9, 16, 25]
							
						

Normal List with Refactoring

							
								a_list = [1,2,3,4,5]

								def square_list(a_list):
									for i in range(len(a_list)):
										a_list[i] *= a_list[i]

								square_list(a_list)
								print(a_list)

								# Output
								[1, 4, 9, 16, 25]
							
						

List Comprehension without Conditional

							
								a_list = [1,2,3,4,5]

								def square_list(a_list):
									return [x*x for x in a_list]

								print(square_list(a_list))

								#Output 
								[1, 4, 9, 16, 25]
							
						

List Comprehension with Conditional

							
								a_list = [1,2,3,4,5]

								def square_list(a_list):
									return [x*x for x in a_list if x % 2 == 0]
								
								print(square_list(a_list))
								
								# Output
								[4, 16]								
							
						

Set Comprehension with Conditional

							
								a_list = [1,2,3,4,5]

								def square_list(a_list):
									return {x*x for x in a_list if x % 2 == 0}

								print(square_list(a_list))

								# Output
								set([16, 4])
							
						

Dictionary Comprehension

							
								my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4, }

								squared_dict = {k:v*v for (k,v) in my_dict.items()}
								print(squared_dict)
							
						

Labs

TODO("Link Lab")

Recursion

Recursion is a function that calls itself until a condition is met

							
								# This program has a recursive function.

								def main():
									message()

								def message():
									print('This is a recursive function.')
									message()

								# Call the main function.
								main()

							
						
							
							Program Output

								This is a recursive function.
								This is a recursive function.
								This is a recursive function.
								This is a recursive function.

							
						
							
							def countdown(n):
								if n <= 0:
									print('Blastoff!')
								else:
									print(n)
									countdown(n-1)

							
						

Function call

							
							>>> countdown(3)

							
						

Function call

							
							3
							2
							1
							Blastoff!

							
						

Base Case and Recursive Case

  • Base Case
    • If the problem can be solved now, then the function solves it and returns
  • Recursive Case
    • If the problem cannot be solved now, then the function reduces it to smaller similar problems and calls itself to solve the smaller problem.

Recursive program

							
							 	1  # This program has a recursive function.
								2
								3  def main():
								4      # By passing the argument 5 to the message
								5      # function we are telling it to display the
								6      # message five times.
								7      message(5)
								8
								9  def message(times):
								10      if times > 0:
								11          print('This is a recursive function.')
								12          message(times − 1)
								13
								14  # Call the main function.
								15  main()

							
						

Recursive Ouput

							
							Program Output

								This is a recursive function.
								This is a recursive function.
								This is a recursive function.
								This is a recursive function.
								This is a recursive function.

							
						

Problem solving with Recursion

							
							A problem can be solved with recursion if it can be broken down into smaller problems that are identical in structure to the overall 								problem.
							
						

Recursion vs Iteration

							
							Any problem that can be solved recursively can also be solved with a loop.
							
						

Repetitive problems

							
							If the problem can be solved now, without recursion, then the function solves it and returns

							If the problem cannot be solved now, then the function reduces it to a smaller but similar problem and calls itself to solve the 									smaller problem
							
						

Using Recursion to Calculate the Factorial of a Number

							
						If n  = 0 then       n! = 1
						If n  > 0 then       n! = 1 × 2 × 3 ×  . . . × n
							
						

Using Recursion to Calculate the Factorial of a Number

							
						If n  = 0 then       factorial(n) = 1
						If n  > 0 then       factorial(n) = 1 × 2 × 3 ×  . . .  ×  n
							
						

Using Recursion to Calculate the Factorial of a Number

							
						If n = 0 then       factorial(n) = 1
							
						

Using Recursion to Calculate the Factorial of a Number

							
						If n > 0 then       factorial(n) = n × factorial(n − 1)
							
						

Using Recursion to Calculate the Factorial of a Number

							
						If n  = 0 then       factorial(n) = 1
						If n  > 0 then       factorial(n) = n × factorial(n − 1)			
							
						

Recursion program to Calculate the factorial of a number

							
						 	1  # This program uses recursion to calculate
							2  # the factorial of a number.
							3
							4  def main():
							5      # Get a number from the user.
							6      number = int(input('Enter a nonnegative integer: '))
							7
							8      # Get the factorial of the number.
							9      fact = factorial(number)
							10
							11      # Display the factorial.
							12      print('The factorial of', number, 'is', fact)
							13
							
						

Using Recursion to Calculate the Factorial of a Number

							
						14  # The factorial function uses recursion to
						15  # calculate the factorial of its argument,
						16  # which is assumed to be nonnegative.
						17  def factorial(num):
						18      if num == 0:
						19          return 1
						20      else:
						21          return num * factorial(num − 1)
						22
						23  # Call the main function.
						24  main()
							
						

Using Recursion to Calculate the Factorial of a Number

							
						Program Output 

						Enter a nonnegative integer: 4 
						The factorial of 4 is 24
							
						

Using Recursion to Calculate the Factorial of a Number

							
								return num * factorial(num − 1)
							
						

Direct and Indirect Recursion

							
							Direct: calls itself
							Indirect: Function A calls Function B, which calls Function C, which calls Function A.
							
						

Checkpoint

							
						1. It is said that a recursive algorithm has more overhead than an iterative algorithm. What does this mean?
						2. What is a base case?
						3. What is a recursive case?
						4. What causes a recursive algorithm to stop calling itself?
						5. What is direct recursion? What is indirect recursion?
							
						

Examples of Recursive Algorithms

							
						Demo Labs
							
						

What will the following program display?

							
					def main():
						num = 0
						show_me(num)
					def show_me(arg):
						if arg < 10:
						show_me(arg + 1)
						else:
						print(arg)
					main()
												
						

What will the following program display?

							
					def main():
						num = 0
						show_me(num)
					def show_me(arg):
						print(arg)
						if arg 10:
						show_me(arg + 1)
					main()
												
						

The following function uses a loop. Rewrite it as a recursive function that performs the same operation.

							
					def traffic_sign(n):
						while n > 0:
							print('No Parking')
							n = n > 1
												
						

Programming Performance Labs

							
								1. Recursive Printing
								2. Recursive Lines
								3. Largest List item
								4. Recursive List Sum

												
						

Recursion to find factorial of a number

Lets take a look at solving for n!. As a quick reminder n! is defined as:

							
								n! = n x (n-1) x (n-2) x (n-3) x...x 3 x 2 x 1
								4! = 4 x 3 x 2 x 1 = 24
								
							Base case:
								If n = 0 then   n! = 1
							or  If n = 0 then   factorial(n) = 1
							
							Recursive case:
								If n > 0 then   n! = 1 x 2 x 3 x ... n
							or  If n > 0 then   factorial(n) = n x factorial(n-1)
														
							
						

Python Translation:

							
								def recursive_factorial(n):
									#base case
									if n == 0:
										return 1
									#recursive case
									else:
										return n * recursive_factorial(n-1)					
							
						

Endless Recursion

Be sure that every time you write a recursive function that you can control the number of times it will be executed.

							
								# Endless recursion
								def forever_recursion():
									annoying_message()
								
								def annoying_message():
									print('Nudge Nudge, Wink Wink, Say No More Say No More')
									message()										
							
						

Recursion for the Fibonacci Series

A very common way to present recursion is by writing a program to calculate Fibonacci numbers. After the second number, every number in the series is the sum of the two previous numbers. The sequence is the following: 0,1,1,2,3,5,8,13,21,34,55,89,144,233,...

							
								A recursive function can have multiple base cases. Both of them return a value without making a recursive call.
																			
								Base case:
									If n = 0 then   fibonacci(n) = 0
									If n = 1 then   fibonacci(n) = 1

								Recursive case:
									If n > 1 then   fibonacci(n) = fibonacci(n-1) + fibonacci(n-2)						
							
						

Translate to Python

							
								def fibonacci(n):
									if n == 0:
										return 0
									elif n == 1:
										return 1
									else:
										return fibonacci(n-1) + fibonacci(n-2)
							
						

Labs

TODO("Link Lab")

Closures

  • A Closure is a function object that remembers values in enclosing scopes
  • If you have written a function that returned another function

Closure Example

							
								def generate_power_func(n):

								def nth_powah(x):
									return x**n
								return nth_powah

							x = generate_power_func(10)
							print(x)
							
						

Why use Closures

  • Closures can avoid the use of global values and provide some form of data hiding.
  • They provide a layer of simplicity

Why to avoid Closures

  • They are harder to debug
  • They may not always be cleaner
  • They can get complex quickly

Iterators

  • An iterator is an object with a state that remembers where it is during iteration
  • Building your own iterator means that you can save memory space

Iterator Example

							
								>>> x = iter([1, 2, 3, 4])
								>>> print(x)
								<list_iterator object at 0x0000029C29CA6A00>
								next(x)
								1
								next(x)
								2
								next(x)
								3
								next(x)
								4
								next(x)
                                StopIteration
							
						

Generators

  • A generator is a function that produces a sequence of values to iterate through rather than a single value.
  • Yield is similar to return however yield produces a sequence of values.
  • If there is a yield in the body of the function then it is a generator.

Generators Example

							
								def yrange(n):
									i = 0
									while i < n:
										yield i
										i += 1
								my_gen = yrange(10)
								print(my_gen)
								for i in my_gen:
									print(i)
							
						

Generators Output

							
								# output
								<generator object yrange at 0x007F3328>
								0
								1
								2
								3
								4
								5
								6
								7
								8
								9
							
						

Labs

TODO("Link Lab")

Questions?

Summary

  • Function Scope
    • Local
    • Enclosed
    • Global
    • Built-In
    • Modification of Global Variables
  • User Functions
  • Calling Functions
  • Parameters and arguments
    • Parameters
    • arguments
    • Copy vs Reference
    • Modification of Parameters
    • Default Parameters
    • Command-Line Arguments
    • Returning
    • Pass By Reference
  • Lambda Functions
    • Lambda Function Features
    • Lambda Function Breakdown
    • CommonUses
  • List Comprehension
    • Normal List
    • Normal List with Refactoring
    • List Comprehension without Conditional
    • List Comprehension with Conditional
    • Comprehension with Conditional
    • Dictionary Comprehension
  • Closures
    • How to use Closures
    • Closure Risks
  • Iterators
    • How to use Iterators
  • Generators

Questions?

Summary

  • Scope
  • User Functions
  • Parameters and Arguments
  • Commandline Arguments
  • Returning
  • Pass By Reference
  • Lambda Functions
  • List Comprehension
  • Closures
  • Iterators
  • Generators