So here's some good news!
A function are chunks of reusable, modular code, that allows a programmer to write more efficient programs.
Functions can be inbuilt, inherited from a library, or user defined. We will cover all of them in this tutorial. Let's first look at Inbuilt functions. As always, you can read more about these in Python's official documentation on Inbuilt Functions.
In [1]:
# Some functions already covered
nums = [num**2 for num in range(1,11)]
print(nums) #print is a function, atleast Python 3.x onwards
In [2]:
# In Python 2.x - Not a function, it's a statement.
# Will give an error in Python 3.x
print nums
In [3]:
len(nums)
Out[3]:
In [4]:
max(nums)
Out[4]:
In [5]:
min(nums)
Out[5]:
In [6]:
sum(nums)
Out[6]:
In [7]:
nums.reverse()
nums
Out[7]:
In [8]:
# Reverse a string
# Notice how many functions we use
In [9]:
word = input("Enter a word:")
word = list(word)
word.reverse()
word = ''.join(word)
word
Out[9]:
In [10]:
word = input("Enter a word: ")
In [11]:
word = list(word)
word
Out[11]:
In [12]:
word.reverse()
In [13]:
word = "".join(word)
word
Out[13]:
So as you can see, you have used a lot of functions already.
Now compare the Python code above to one way to handle a similar problem in C. Just to be clear, C is a very powerful langauage, so this isn't meant to show C in poor light, but to show you an area where Python is much more user friendly.
This image above is from the awesome XKCD series. If you're not familiar with it, I encourage you to check them out, hilarious geek humour!
We will often have to import a lot of functions from existing libraries in Python.
Why? Because someone else very generously wrote hundreds or thousands of lines of codes so we don't have to. The large library base of Python is one of the reasons Data Scientists use it.
This is how the import syntax works:
Let's see a few examples below.
In [14]:
# Import the library
import random
# Initiate a for loo
for i in range(5):
# x is equal to a random value, that we got from the library named random, and the function named random()
x = random.random()
print(round(x,2))
In [15]:
# Circumference of a circle
from math import pi
radius = int(input("Enter the radius in cm: "))
c = 2*pi*radius
area = pi*(radius**2)
print("The circumference of the circle is: ",c)
print("The area of the circle is: ", area)
First off, what I refer to as libraries, others might also refer to as Modules.
Next - it's generally bad to use "from library import *"
Quoting from the Google Python Style Guide:
Use `import x` for importing packages and modules.
Use `from x import y` where x is the package prefix and y is the module name with no prefix.
Use `from x import y as z` if two modules named y are to be imported or if y is an inconveniently long name.
For example the module sound.effects.echo may be imported as follows:
`from sound.effects import echo
...
echo.EchoFilter(input, output, delay=0.7, atten=4)`
Do not use relative names in imports. Even if the module is in the same package, use the full package name. This helps prevent unintentionally importing a package twice.
Don't worry if you haven't understood all of that, I just want you to recall some of the keywords mentioned here when we start implementing these principles.
By now, you should have noticed a pattern. Every new technique we learn, is progressively more and more powerful. And we also combine many of the techniques we have already learnt.
User defined functions are simply a way for a user - you - to define code blocks that do exactly what you want. Don't want to write code to say "Hello User!" every time? Define a function!
As usual - very simple syntax.
def function_name(optional_input):
inputs or variables
functions like print
a return function if needed
Let's break this down in our examples.
In [16]:
# Function to say hello to the user
def say_hello():
name = input("What's your name? ")
print("Hello ", name,"!")
In [17]:
say_hello()
In [18]:
list_a = ["a", 1, 42, 19, "c", "23",1,2,3,4,5,6]
type(list_a)
Out[18]:
In [19]:
for i in list_a:
print(type(i))
In [20]:
len(list_a)
Out[20]:
In [21]:
def list_scorer(list_name):
if type(list_name) == list:
print("Correctly identified a list of length,",len(list_name),"items.")
for i in list_name:
print(type(i))
else:
print("This is not a list.")
In [22]:
list_scorer(list_a)
In [23]:
list_scorer("Hello")
Let's also look at the 'return' statement. When you print something using the standard print syntax:
print("Hello World!")
print(2**2)
it only displays that output to the screen. So in the case of 2**2 which is 4, the value is merely displayed, but it cannot be used by the program for any purpose.
For that, we 'return' the value to the program.
In [24]:
def sq_num(num):
squared = num ** 2
return squared
In [25]:
sq_num(10)
Out[25]:
As with the print statement, you can perform this in a single line:
In [26]:
def sq_num2(num):
return num**2
In [27]:
sq_num2(5)
Out[27]:
For a data scientist, writing efficient functions can come in really handy during the data cleaning phase. Let's see one example.
In [28]:
def clean_up(tel_num):
result = ""
digits = {"0","1","2","3","4","5","6","7","8","9"}
for character in tel_num:
if character in digits:
result = result + character
return result
In [29]:
client_phone_num = "+1-555-123-1234 Barone Sanitation (Call only day time)"
clean_up(client_phone_num)
Out[29]:
One important thing while dealing with functions. What happens inside a function, stays in a function.
None of the variables defined inside a function can be called outside of it. Want to test it out?
In [30]:
def cubist(num):
cubed = num**3
return cubed
In [31]:
cubist(3)
Out[31]:
In [32]:
print(cubed) # Will give an error
Remember, what happens in a function, stays in a function! Except return. That will come back!
Let's write a function to generate a password. In input n will be an integer of any length. Of course, for practical purposes, this could be useless if we enter 100 or 100000.
Let's begin with some starter code.
import random
import string
random.choice(string.ascii_letters)
This will generate a random string. Let's find a way to use this to generate a password of any length.
In [33]:
import random
import string
random.choice(string.ascii_letters)
def pass_gen(n):
# Initiate a blank password
password = ""
# Remember, n+1
for letter in range(1,n+1):
# We add a random character to our blank password
password = password + random.choice(string.ascii_letters)
return password
In [34]:
pass_gen(8)
Out[34]:
Here's a challenge for you. Can you modify the above code to make sure that a password is atleast 6 character, but not more than 20 character. The first letter must be a capital letter, and there has to be atleast 1 number. The code below can help with generating random capitalised characters, and numbers.
random.choice('ABCDEFGHIJKLMNOPQRSTUVXYZ')
random.choice('123456789')
It's ok to struggle with this - the more you see different patterns of code, the more you learn. Don't panic if you can't figure it out in 2 minutes. Start out with writing some pseudo-code in plain English (or your native language), tracing out how you would go about this.
In [ ]:
# Your code below