Sei sulla pagina 1di 13

Function

Why Use Functions ?

Stay DRY - Don't Repeat Yourself!

Clean up and prevent code duplication


"Abstract away" code for other users

Imagine if you had to rewrite the "print()" function for every program
you wrote

Function Structure
def name_of_function()

# block of runnable code

def say_hi()
   print('Hi!')

say_hi()
# Hi

Returning Values from Functions

def say_hi()
   return 'Hi!'

greeting = say_hi()
print(greeting) # 'Hi!'

return

Exits the function


Outputs whatever value is placed after the return keyword
Pops the function off of the call stack

learn more about callstack

Example

Coin Flips
from random import random

def flip_coin()
   r = random()
   if r > 0.5:
       return "Heads"
   else:
       return "Tails"

print(flip_coin())

Generating Evens

1
def generate_evens()
   return [num for num in range(1,50) if num % 2 0]
2
def generate_evens()
   result = []
   for x in range(1,50)
       if x % 2 0:
           result.append(x)
   return result

Parameter
Parameters vs Arguments

A parameter is a variable in a method definition.


When a method is called, the arguments are the data you pass into the
method's parameters.
Parameter is variable in the declaration of function.
Argument is the actual value of this variable that gets passed to function.

Variables that are passed to a function - think of them as placeholders that get
assigned when you call the function.

def multiply(first, second)


   return first * second
# you can call your parameters anything!
multiply(5,5) # 25
multiply(2,2) # 4

Naming Parameters

# Not great
def print_full_name(string1, string2)
   return(f"Your full name is {string1} {string2}")

# Better
def print_full_name(first_name, last_name)
   return(f"Your full name is {first_name} {last_name}")

Example
def yell(word)
   return f"{word.upper()}!"

print(yell("hello"))

Common Return Mistakes


1. Returning too early in a loop

def sum_odd_numbers(numbers)
   total = 0
   for num in numbers:
       if num % 2 != 0:
           total += num
       return total

2. Unnecessary else

def is_odd_number(num)
   if num % 2 != 0:
       return True
   else:
       return False

def is_odd_number(num)
   if num % 2 != 0:
       return True
   return False

Default Parameters

def add(a,b)
   return a+b

add() # does not work!

def add(a=10, b=20)


   return a+b

add() # 30
add(1,10) # 11

Example
def show_information(first_name="Stranger", is_instructor=False)
   if first_name "Stranger" and is_instructor:
       return "Welcome back instructor Colt!"
   elif first_name "Stranger":
       return "I really thought you were an instructor "
   return f"Hello {first_name}!"

show_information() # "I really thought you were an instructor "


show_information(is_instructor=True) # "Welcome back instructor Stranger!"
show_information('Brandon') # Hello Brandon!

Why have Default Params ?

Allows you to be more defensive


Avoids errors with incorrect parameters
More readable examples!

What can Default Parameters be ?

Anything! Functions, lists, dictionaries, strings, booleans - all of the above!

def add(a,b)
   return a+b

def math(a,b, fn=add)


   return fn(a,b)

def subtract(a,b)
   return a-b

math(2,2) # 4

math(2,2, subtract) # 0

Scope
Variables created in functions are scoped in that function!

instructor = 'Colt'

def say_hello()
   return f'Hello {instructor}'

say_hello() 'Hello Colt'

def say_hello()
   instructor = 'Colt'
   return f'Hello {instructor}'

say_hello()

print(instructor) # NameError

Global
total = 0

def increment()
   total += 1
   return total

increment() # Error!

Lets us reference variables that were originally assigned on the global scope

total = 0

def increment()
   global total
   total += 1
   return total

increment() # 1

Nonlocal

Lets us modify a parent's variables in a child (aka nested) function

def outer()
   count = 0
   def inner()
       nonlocal count
       count += 1
       return count
   return inner()

You will not find yourself using the global or nonlocal keyword frequently - but
it's essential to understand for scope!

Documenting functions
Use """ """

Essential when writing complex functions

def say_hello()
   """A simple function that returns the string hello"""
   return "Hello!"

say_hello. doc # 'A simple function that returns the string hello'

Function Extend
* And As Parameters

args
A special operator we can pass to functions
Gathers remaining arguments as a tuple

This is just a parameter - you can call it whatever you want!

Example :

def sum_all_values(*args)
   total = 0
   for val in args:
       total += val

   return total

sum_all_values(1, 2, 3) # 6

sum_all_values(1, 2, 3, 4, 5) # 15

The order does not matter!

def ensure_correct_info(*args)
   if "Colt" in args and "Steele" in args:
       return "Welcome back Colt!"

   return "Not sure who you are "

ensure_correct_info() # Not sure who you are

ensure_correct_info(1, True, "Steele", "Colt")

kwargs
A special operator we can pass to functions

Gathers remaining keyword arguments as a dictionary

Example :

def fav_color( kwargs)


   for person, color in kwargs.items()
       print(f"{person} favorite color is {color}")
   
fav_color(budi = "red", johan = "blue", rudi = "orange")

Parameter Ordering
1. Parameters
2. *args
3. Default Parameters
4. **kwargs

* And As Arguments (Unpacking)

Tuple Unpacking
Using * as an Argument
Argument Unpacking

We can use * as an argument to a function to unpack values

def sum_all_values(*args)
   # there's a built in sum function - we'll see more later!
   return sum(args)

sum_all_values([1, 2, 3, 4]) # nope


sum_all_values((1, 2, 3, 4)) # this does not work either

sum_all_values(*[1, 2, 3, 4]) # 10
sum_all_values(*(1, 2, 3, 4)) # 10

Dictionary Unpacking
Using ** as an Argument

We can use ** as an argument to a function to "unpack" dictionary values into


keyword arguments

def display_names(first, second)


   return f"{first} says hello to {second}"

names = {"first": "Colt", "second": "Rusty"}

display_names(names) # nope

display_names( names) "Colt says hello to Rusty"

Lambdas & Built-in Functions


Normal functions have names...

def first_function()
   return 'Hello!'

first_function() # 'Hello!'

first_function. name # first_function'

But lambdas are anonymous functions!

first_lambda = lambda x: x + 5

first_lambda(10) # 15

first_lambda. name # '<lambda>'

Lambda Syntax
lambda parameters : body of function
add_values = lambda x, y: x + y

multiply_values = lambda x, y: x + y

add_values(10, 20) # 30

multiply_values(10, 20) # 200

Map
Syntax Structure

map(function, iterable)

1. A standard function that accepts at least two arguments, a function and an


"iterable"
2. Iterable - something that can be iterated over (lists, strings,
dictionaries, sets, tuples)
3. Runs the lambda for each value in the iterable and returns a map object
which can be converted into another data structure

l = [1, 2, 3, 4]

doubles = list(map(lambda x: x * 2, l))

evens # [2, 4, 6, 8]

Another Example :

l = [1,2,3,4]

doubles = list(map(lambda x: x*2, l))

evens # [2,4,6,8]

names = [
  {'first':'Rusty', 'last': 'Steele'},
  {'first':'Colt', 'last': 'Steele', },
  {'first':'Blue', 'last': 'Steele', }
]

first_names = list(map(lambda x: x['first'], names))

first_names # ['Rusty', 'Colt', 'Blue']

Filter
There is a lambda for each value in the iterable.
Returns filter object which can be converted into other iterables
The object contains only the values that return true to the lambda
l = [1,2,3,4]

evens = list(filter(lambda x: x % 2 0, l))

evens # [2,4]

Combining filter and map


Given this list of tweets:

users = [
{"username": "samuel", "tweets": ["I love cake", "I love pie", "hello
world!"]},
{"username": "katie", "tweets": ["I love my cat"]},
{"username": "jeff", "tweets": []},
{"username": "bob123", "tweets": []},
{"username": "doggo_luvr", "tweets": ["dogs are the best", "I'm hungry"]},
{"username": "guitar_gal", "tweets": []}
]

Extract inactive users

#extract inactive users using filter:


inactive_users = list(filter(lambda u: not u['tweets'], users))

#extract inactive users using list comprehension:


inactive_users2= [user for user in users if not user["tweets"]]

# extract usernames of inactive users w/ map and filter:


usernames = list(map(lambda user: user["username"].upper(),
filter(lambda u: not u['tweets'], users)))

# extract usernames of inactive users w/ list comprehension


usernames2 = [user["username"].upper() for user in users if not user["tweets"]]

Built-In Functions

all()
Return True if all elements of the iterable are truthy (or if the iterable is
empty)

all([0,1,2,3]) # False

all([char for char in 'eio' if char in 'aeiou'])

all([num for num in [4,2,10,6,8] if num % 2 0]) # True

any()
Return True if any element of the iterable is truthy. If the iterable is empty,
return False.
any([0, 1, 2, 3]) # True

any([val for val in [1,2,3] if val > 2]) # True

any([val for val in [1,2,3] if val > 5]) # False

sorted()
Returns a new sorted list from the items in iterable

# sorted (works on anything that is iterable)

more_numbers = [6,1,8,2]
sorted(more_numbers) # [1, 2, 6, 8]
print(more_numbers) # [6, 1, 8, 2]

users = [
{"username": "samuel", "tweets": ["I love cake", "I love pie", "hello
world!"]},
{"username": "katie", "tweets": ["I love my cat"]},
{"username": "jeff", "tweets": [], "color": "purple"},
{"username": "bob123", "tweets": [], "num": 10, "color": "teal"},
{"username": "doggo_luvr", "tweets": ["dogs are the best", "I'm hungry"]},
{"username": "guitar_gal", "tweets": []}
]

# To sort users by their username


sorted(users,key=lambda user: user['username'])

# Finding our most active users


# Sort users by number of tweets, descending
sorted(users,key=lambda user: len(user["tweets"]), reverse=True)

# ANOTHER EXAMPLE DATA SET==================================


songs = [
{"title": "happy birthday", "playcount": 1},
{"title": "Survive", "playcount": 6},
{"title": "YMCA", "playcount": 99},
{"title": "Toxic", "playcount": 31}
]

# To sort songs by playcount


sorted(songs, key=lambda s: s['playcount'])

max() & min()


Max

Return the largest item in an iterable or the largest of two or more arguments.
# max (strings, dicts with same keys)

max([3,4,1,2]) # 4
max((1,2,3,4)) # 4
max('awesome') # 'w'
max({1:'a', 3:'c', 2:'b'}) # 3

Min

Return the smallest item in an iterable or the smallest of two or more


arguments.

# min (strings, dicts with same keys)

min([3,4,1,2]) # 1
min((1,2,3,4)) # 1
min('awesome') # 'a'
min({1:'a', 3:'c', 2:'b'}) # 1

Exercise

names = ['Arya', "Samson", "Dora", "Tim", "Ollivander"]

# finds the minimum length of a name in names


min(len(name) for name in names) # 3

# find the longest name itself


max(names, key=lambda n:len(n)) #Ollivander

songs = [
{"title": "happy birthday", "playcount": 1},
{"title": "Survive", "playcount": 6},
{"title": "YMCA", "playcount": 99},
{"title": "Toxic", "playcount": 31}
]

# Finds the song with the lowerest playcount


min(songs, key=lambda s: s['playcount']) "title": "happy birthday",
"playcount": 1}

# Finds the title of the most played song


max(songs, key=lambda s: s['playcount'])['title'] #YMCA

reversed()
Return a reverse iterator.

more_numbers = [6, 1, 8, 2]
reversed(more_numbers) # <list_reverseiterator at 0 1049f7da0>
print(list(reversed(more_numbers))) # [2, 8, 1, 6]

abs()
Return the absolute value of a number. The argument may be an integer or a
floating point number.
abs(-5) # 5
abs(5)  # 5

sum()
Takes an iterable and an optional start.
Returns the sum of start and the items of an iterable from left to right and
returns the total.
start defaults to 0

sum([1,2,3,4]) # 10

sum([1,2,3,4], -10) # 0

round()
Return number rounded to ndigits precision after the decimal point. If ndigits
is omitted or is None, it returns the nearest integer to its input.

round(10.2) # 10
round(1.212121, 2) # 1.21

zip()
Make an iterator that aggregates elements from each of the iterables.
Returns an iterator of tuples, where the i-th tuple contains the i-th
element from each of the argument sequences or iterables.
The iterator stops when the shortest input iterable is exhausted.

first_zip = zip([1,2,3], [4,5,6])

list(first_zip) # [(1, 4), (2, 5), (3, 6)]

dict(first_zip) # {1 4, 2 5, 3 6}

With argument unpacking

five_by_two = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]

list(zip(*five_by_two))

[(0, 1, 2, 3, 4), (1, 2, 3, 4, 5)]

Complex Example, Combining with Map

midterms = [80,91,78]
finals = [98,89,53]
students = ['dan', 'ang', 'kate']

# returns dict with {student:highest score} USING DICT COMP


# {'dan': 98, 'ang': 91, 'kate': 78}
final_grades = {t[0] max(t[1], t[2]) for t in zip(students, midterms, finals)}
# returns dict with {student:highest score} (same thing as above) USING
MAP+LAMBDA
# {'dan': 98, 'ang': 91, 'kate': 78}
final_grades = dict(
zip(
students,
map(
lambda pair: max(pair),
zip(midterms, finals)
)
)
)

# returns dict with student:average score


# {'dan': 89.0, 'ang': 90.0, 'kate': 65.5}
avg_grades = dict(
zip(
students,
map(
lambda pair: ((pair[0]+pair[1])/2),
zip(midterms, finals)
)
)
)

Potrebbero piacerti anche