#!/usr/bin/env python # coding: utf-8 # ### Built-in functions # # Python provides a set of functions already built-in. You are already very familiar with one of them: # In[ ]: # Here print is the function # Within parentheses we pass ONE parameter, the string with the message print("Oh yeah, I am a function! I print things on the screen") # In[ ]: # The print function can take more than one parameter # For example below we pass three strings as parameters name = "Panos" print("Hi", name, "How are you") # - You have already encountered `len`, `sum`, `max`, and `min`. # In[ ]: nums = [3, 41, 12, 9, 74, 15] # len() takes as a parameter a string (and returns its length in characters) # or a list/set/dictionary/... (and returns the number of elements) print("Length:", len(nums)) # In[ ]: # max() / min() takes as a parameter a *list* and returns # the maximum or minimum element print("Max:", max(nums)) print("Min:", min(nums)) # In[ ]: # sum() gets as input a list of numbers and returns their sum print("Sum:", sum(nums)) # - We have also used various type conversion functions, such as `set`, `list`, and `tuple`. We can also do type conversions with `int`, `float`, and `str`: # In[ ]: # Convert to integer int(3.7) # In[ ]: # Convert to float float(2) # In[ ]: # Convert to float <- also works with strings! float('6.8') # In[ ]: # Convert to string str(233) # - And, we used `type` to find out the type of a given variable. # In[ ]: # Type for a float x = 1.99 type(x) # In[ ]: # Type for a string y = 'abc' type(y) # In[ ]: # Type for a list z = ['a', True, 3] type(z) # In[ ]: # Type for an element of a list type(z[1]) # In[ ]: # Type for all elements of a list [type(i) for i in z] # - In a variety of contexts, we also used the `range` and `sorted` functions. # In[ ]: list(range(-10,10,2)) # In[ ]: # sorted() has a list as input and returns the list with the elements sorted sorted([5,23,3,77,9,12]) # - You may also have seen the `round` function: # In[ ]: round(3.14159, 2) # The list at https://docs.python.org/3/library/functions.html contains all the built-in functions of Python. # **As a general rule of thumb, avoid using these bult-in function names as variable names.** # ### Functions from Libraries # # We can also add more functions by `import`-ing libraries. For example, we can import the `math` library. # In[ ]: import math # In[ ]: # math.fabs returns the absolute value math.fabs(-2345) # In[ ]: # math.fabs takes the factorial math.factorial(5) # In[ ]: math.factorial(5) == 5*4*3*2*1 # Another commonly used library is the `random` library that returns random numbers. # In[ ]: import random # In[ ]: # random.random() returns random values from 0 to 1 for i in range(10): print(round(random.random(), 3)) # In[ ]: #random.choice() can be used to select items from a list for i in range(5): print(random.choice(['a','b','c','d'])) # And, you have seen the `time` package # In[ ]: import time time.sleep(2) # ### User Defined Functions # # # ** See also Examples 18, 19, 20, and 21 from Learn Python the Hard Way ** # # Functions assign a name to a block of code the way that variables assign names to bits of data. This seemingly benign naming of things is incredibly powerful; allowing one to reuse common functionality over and over. Well-tested functions form building blocks for large, complex systems. As you progress through Python, you'll find yourself using powerful functions defined in some of Python's vast libraries of code. # # # Function definitions begin with the `def` keyword, followed by the name you wish to assign to a function. Following this name are parentheses, `( )`, containing zero or more variable names, those values that are passed into the function. There is then a colon, followed by a code block defining the actions of the function: # # def function_name(function_input) # ... function actions ... # #### Printing "Hi" # # Let's start by looking at a function that performs a set of steps. # In[ ]: def print_hi(): print("hi!") # In[ ]: for i in range(10): print_hi() # * Of course, most functions have also one or more _parameters_. For example, the function below will accept the name as a parameter, and then print out the message "HI _name_", where _name_ is the value of the parameter that we pass to the function. The function will also convert the _name_ into uppercase: # In[ ]: def hi_you(name): ''' This function takes as input/parameter the variable name And then prints in the screen the message HI ! where is the content of the name variable converted to uppercase ''' print("HI", name.upper()) # In[ ]: names = ['Panos', 'Peter', 'Kylie', 'Jennifer', 'Elena'] for n in names: hi_you(n) # * Let's modify the `hi_you` to take as input a *list* of names and print out all of them # In[ ]: def hi_you_all(list_of_names): ''' This function takes as input/parameter list_of_names And then prints in the screen the message HI ! for all the names in the list_of_names. The paramater 'names' is a list of strings, with every string being a name that we want to print out ''' for name in list_of_names: print("HI", name.upper(), "!") # Alternatively, we could reuse the function hi_you(name) # hi_you(name) # In[ ]: names = ['Panos', 'Peter', 'Kylie', 'Jennifer', 'Elena'] hi_you_all(names) # #### The `return` statement # # Example of computing a math function # In[ ]: # The functions are often designed to **return** the # result of a computation/operation def square(num): squared = num*num return squared # In[ ]: x = square(3) # notice that square RETURNS a value that # we store in variable x # this is in contrast to hi_you and hi_you_all # that just printed out messages on the screen print(x) # In[ ]: for i in range(15): print(f"The square of {i} is {square(i)}") # Note that the function `square` has a special keyword `return`. The argument to return is passed to whatever piece of code is calling the function. In this case, the square of the number that was input. # #### Solving the quadratic equation # # Here is another example of a function, for solving the quadratic equation # $$ a*x^2 + b*x + c = 0$$ # Recall that the quadratic formula is: # $$ x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$$ # In[ ]: import math a = 4 b = -32 c = 1 # In[ ]: # We want to solve the quadratic equation a*x^2 + b*x + c = 0 # We have two solutions: s1 = (-b + math.sqrt(b**2 - 4*a*c) ) / (2*a) s2 = (-b - math.sqrt(b**2 - 4*a*c) ) / (2*a) print(f"Solution 1: {s1:.3f}") print(f"Solution 2: {s2:.3f}") # Let's see an example of how a function can return "multivalued" results using tuples/lists. # In[ ]: def quadratic(a,b,c) : # Function takes a,b,c as input s1 = (-b + math.sqrt(b**2 - 4*a*c))/(2*a) s2 = (-b - math.sqrt(b**2 - 4*a*c))/(2*a) return s1, s2 # Note that we can return multiple things # The "return" value does not have to be a single value # A function can even return a list, tuple, dictionary, etc. # In[ ]: # Observe that the function returns a tuple with s1 and s2 sol = quadratic(a,b,c) print("Solutions:", sol ) print("Solutions:", sol[0] ) print("Solutions:", sol[1] ) # In[ ]: # If we want, we can even assign a value to each item returned, like so: sol1, sol2 = quadratic(a,b,c) print("Solutions:", sol1 ) print("Solutions:", sol2 ) # In[ ]: # We can even check that the value of the discriminant # is positive before returning a result def quadratic(a,b,c): discr = b**2 - 4*a*c if discr < 0: # We will not compute return None # "None" is a special value, meaning "nothing" s1 = (-b + math.sqrt(b**2 - 4*a*c))/(2*a) s2 = (-b - math.sqrt(b**2 - 4*a*c))/(2*a) return s1, s2 # In[ ]: quadratic(6,1,9) # In[ ]: quadratic(6,27,9) # In[ ]: ## A COMMON MISTAKE: # Using multiple return statements # Why? After we execute the first return, # we do not execute anything below that def quadratic_s1_only(a, b, c): discr = b**2 - 4*a*c if discr < 0: # We will not compute return None # "None" is a special value, meaning "nothing" s1 = (-b + math.sqrt(b**2 - 4*a*c))/(2*a) s2 = (-b - math.sqrt(b**2 - 4*a*c))/(2*a) return s1 # solution 1 return s2 # solution 2, BUT this will never be executed # In[ ]: quadratic_s1_only(a, b, c) # #### Example function: Cleaning up a string # We can use the `string` library to get a list of all letters by typing `string.ascii_letters`. # In[ ]: # This code prints all the letters in the alphabet import string string.ascii_letters # In[ ]: # this function takes as input a phone string variable # and removes anything that is not a letter or space def clean(text): result = "" letters = string.ascii_letters + " " for c in text: if c in letters: result = result + c return result # In[ ]: p = "(800) 555-1214 Phone number" print(clean(p)) # #### Exercises # # * Write a function `in_range` that checks if a number `n` is within a given range `(a,b)` and returns True or False. The function takes n, a, and b as parameters. # # # In[ ]: # Your function here # **Answer:** # def in_range(n, a, b): # if n>a and n # def dedup(l): # return sorted(list(set(l))) # - Write a function to test whether two strings are equal, ignoring capitalization. # In[ ]: # Your function here # **Answer**: # def are_equal(s1,s2): # if s1.lower() == s2.lower(): # return True # else: # return False # are_equal("potato", "PoTATo") # are_equal("potato", "PoTAToes") # * Write a function that generates a random password with `n` letters. The value `n` should be a parameter. # In[ ]: # This code generates one random letter import random random.choice(string.ascii_letters) # Your function here # **Answer:** # def random_letter(): # return random.choice(string.ascii_letters) # def random_password(n): # password = '' # for i in range(0,n): # password+= random_letter() # return password