Function is an important component for any programming languages. A function is a set of code which can be run at once when called.
The syntax of a function:
#Here is the definition of a function named func
def func(a, b): # func is a function name which you will use for reference. a and b are parameters
statement1
statement2
return result
# here is how we call a function
func(3,4) # 3, 4 are two (positional) arguments which we pass to the fucntion func, and which correspond to the two parameters by position.
func(a=3, b=4) # this time we explicitly assign two arguments to the two parameters.
print(x)
print(y)
Glossary:
Parameter Vs. Argument: Parameters are variables used by a function definition to receive passed-in values when the function is called. Arguments are values that are passed into a function when the function is invoked/called. Oftentimes these two terms are used interchangeably.
#let's define a function that take 2 arguments to do an addition operation
def f(a,b):
c = a+b
print(c)
# Now let's call this function to calcuate 3+4
f(3,4)
f(a=3, b=4)
f(b=4, a=3)
def with_return(a,b):
return (a, b)
x = with_return(3,4)
print(x,type(x))
Parameters can have default values.
def add_or_sub(a, b, mode = 'add'): # mode has a default value.
if mode == 'add':
print(a+b) # if mode is True, do addition
else:
print(a-b) # if mode is False, do subtraction
add_or_sub(4,3)
add_or_sub(4,3,'add')
add_or_sub(4,3,'else')
In Python, a function can have no function name, which shortens your code (highly efficient and heavily used in Pandas). In order to create anonymous functions, we will need to create a lambda statement.
Syntax:
varName = lambda argument_list: expression
It is noted that a lambda can take more than 1 arguments, but can only have one expression. That expression will be evaluated and returned.
plus2 = lambda x: x+2 # basically we assign a function to a variable
plus2(3)
The anonymous function above is actually equivalent to the code below written in a traditional programming way.
def plus2(x):
return x+2
plus2(3)
We will re-visit the lambda expression when we talk about Pandas.
#Return the absolute value of a number
abs(-4.2)
#Create a dictionary object
x = dict()
print(type(x))
# create a set object
x = set([3,3,4])
print(x)
#Returns an enumerate object
list_x = ['Tom',"Jerry","Kevin"]# list_x is a list
enumerate_x = enumerate(list_x) # enumerate_x is turned into an enumerate object
for x in list_x:
print(x)
for x in enumerate_x:
print(x)
#get the length of an object (such as string, tuple, list, dictionary,set)
a = [2,3,4]
print(len(a))
#get a sum of all the elements in a sequence
a = [3,4,5]
print(sum(a))
#get the type of an object
print(type('time'))
#returns the largest item in a iterable object or a set of numbers
max(2,3,4)
max([2,3,4])
#returns the smallest item
min(2,3,4)
min([2,3,4])
map function, map(), a very powerful built-in function, is used when you want to apply a function (usually a lambda function) to all the elements of an iterable. The syntax is:
map_object = map(function, iterable)
#assuming we have a list object, [1,2,3,4,5]
#my goal is to apply a arithmetic operation on each element of this list, x*10+1
#The expected result is [11,21,31,41,51]
a = [1,2,3,4,5]
result = map(lambda x: x*10, a)
for item in result:
print(item)
A concept that is closely connected to functions is the scope of variables. Scope refers to the visibility of variables. In other words, which part of your code can see or use which variables. Every variable has an associated scope. There are two kinds of scopes, global scope and local scope.
a = 5 # a is a global variable
def func():
print(a) #Let's see if a is accessible from inside a function.
func() #let's call this function
def func():
thislocal = 6 #thislocal is a local variable that can only seen inside its own function.
print(thislocal)
func()
print(thislocal)
As you can tell, a Name error was thrown out by Python on print(thislocal)
saying b is not defined
global_a = 5
def func():
global_a = 4
print(global_a) #Guess which a is called? or the two as are referring to the same value?
func()
print(global_a)
What if we want to change the global values from within a function? Use global keyword
a = 5
def func():
global a # From this moment on, this local variable a is linking to the global one.
a = 4
print(a)
func()
print(a)
Rules:
a = [1,2,3]
b = [10,20,30]
#ge the length of a list
len(a)
In python, the indexing starts from 0, which may be differnt from other languages (e.g.,R and Matlab ).
a = [1,2,3]
print(a[0])
What if the list is too long ,and I want to print out the last element? Please use -1
a = [1,2,3,4,6,7]
a[-1]
b = a[0:2] # start from index-0 and ends at index-3(excluded)
print(b)
#or the start of a slice can be absent
a = [2,3,4,5]
a[:2] #equals a[0:2]
#what if the start and the end of a slice are absent?
a = [2,3,4,5]
a[:] # you got the whole list
What if I want the last 3 elements?
a = [1,2,3,4,5,6,7]
a[-3:]
a = [1,2,3,4,5,6,7]
a[-3:-1] # the element on the position -1 is excluded. This is how slicing works in Python
#finds the index of a certain element
a.index(3)
Since a list object is mutable, let's learn how to change certain elements by using indexing and slicing techniques
let's use indexing to change an element on a certain position.
a = ['a','b','c','d']
a[1] = 2
a
Now let's use slicing to change elements in a row of a list. It is noted if the replacement has the same size as the slice, the replacement is just positioned accordingly. otherwise, the list might be shrunk or expanded.
a = [2,3,4,5]
a[0:2] = ['t','x']
a
#list is shrunk
a = [2,3,4,5]
a[0:2] = ['t']
a
# list is expanded
a = [2,3,4,5]
a[0:2] = [20,30,40,50,60]
a
Can we delete certain elements from a list? yes, you can! Please use del keyword
a = [2,3,4,5,6]
del a[0]
a
a = [2,3,4,5]
del a[:2]
a
The plus sign can be simply used to combine two lists. The second list is appended to the end of the first list.
a = [2,3,4]
b = [5,6,7,8]
a + b
b + a
a = ['Tom',"Jerry"]
b = a * 4
b
Wait! What are methods? Methods are a similar concept as functions, with the exception that methods are associated with certain classes or its instance, objects.
Remember how to call a built-in function? len(A)
when we call a method, it was preceded by a class or object. e.g., A.method()
# append
a = [2,3,4] # this is a list object
a.append(5) # we are calling a list method named append
a
# extend
a = [2,3,4,5]
b = [10,20,30]
a.extend(b)
a
a.append(b)
a
help(list.sort)
#sort
a = [23,68,1,10]
a.sort()
a
# sort method Vs. sort built-in function
a = [23,68,1,10]
x = sorted(a)
x
a # a is not changed by the built-in fucntion because the opertion is not associted with a object
#count
a = [2,3,4,5, 4]
a.count(4)
List comprehension provides a concise way to generate a list object. It is noted list comprehension should only be used when you try to get a list.
[function_expression for x in S]
[function_expression for x in s if condition_expression]
Did you still remember the example we used when introducing map function?
a = [1,2,3,4]
result = list(map(lambda x: x*10,a))
result
let's implement this algorithm using list comprehension.
a = [1,2,3,4]
result = [x*10+1 for x in a]
result
We can also integrate a if-statement inside a list comprehension to add more controls on your workflow.
#This time, we only apply the arithmetic operstion to elements that are larger than 2, and keep the result.
a = [1,2,3,4]
result = [x*10+1 for x in a if x>2]
result
Unlike list objects, tuple objects are immutable, which means once it is initialized, it cannot be changed. In other words, it is only readable, not writable.
a = (2,3,4)#define a tuple object.
The operations mentioned in the section of list can also be used for tuple objects. The only difference is it is illegal to change a tuple object. See an example below which I try to change elements of a tuple.
a[0] = 6
#ways to create a dict
#Way-1, turns a list of list into a diction by using dict() built-in function. The first item is used as a key.
phonelist = [['Kevin','2456'],['Mike','3456'],["Sue",'5567']]
dict_phones = dict(phonelist)
print(dict_phones)
# way-2, uses curly bracket to generate it
dict_phone_list = {'Kevin': '2456', 'Mike': '3456', 'Sue': '5567'}
dict_phone_list
dict_phone_list = {'Kevin': '2456', 'Mike': '3456', 'Sue': '5567'}
len(dict_phone_list)
The concept of order does not exist for dictionary objects. Due to that,we cannot use positional index to refer to elements. Instead, we use keys to get/set values.
dict_1 = {'apple':4, 'grapefruit':10}
dict_1['apple']
What if we use a non-existent key? It will invoke a KeyError, which terminates your program. So, do indexing with caution.
dict_1 = {'apple':4, 'grapefruit':10}
dict_1['banana']
print(dict_1['apple'])
Is there a way that we could detect if a key is inside a dictionary object?
dict_1 = {'apple':4, 'grapefruit':10}
'apple' in dict_1.keys()
'apple' in dict_1
help(list)
dict_phone_list.keys() # is this a method or function?
dict_phone_list.values()
dict_phone_list.items()
dict_phone_list.clear()
len(dict_phone_list)
dict_1 = {'apple':2, 'orange':4, 'banana':10}
dict_2 = {'orange':12, 'grapefruit':1}
dict_1.update(dict_2)
dict_1
Set objects are unordered collections of unique elements. You could get ordered set object with the help of packages
Like other collections, sets support x in set, len(set), and for x in set. Being an unordered collection, sets do not record element position or order of insertion. Accordingly, sets do not support indexing, slicing, or other sequence-like behavior.
All operations of sets can be found here
#way-1 to create a set object, using built-in function, set()
a = [3,4,5,4,5]
b = set(a)
b
#way-2 to create a set object, using curly brackets
a = {3,4,5,6,4}
a
a = {3,4,5,6,4} # it has 5 elements during the initilization
len(a)
a = {3,4,5,6,4}
7 in a
a.__contains__({3,4})
help(set)
a = {2,3,4}
b = {3,4,5}
x = a | b
x
a = {2,3,4}
b = {3,4,5}
x = a & b
x
a = {2,3,4}
b = {3,4,5}
x = a ^ b
x
a = {2,3,4}
b = {3,4,5}
x = a -b
x
a = {3,4,5,6,7}
a.add(8)
a
a.discard(8)
a
a = {3,4,5,6,7,8}
a.clear()
a
help(set)
Imagine you are building a versatile file reader which you want to sell. This tool must be versatile to be impressive, which means it can deal with a variety of file types. e.g., txt files, csv files, excel files, stata files, and so son.
Okay. Now you can think of this file-reader we intend to develop is a package. Then, the next question becomes how many or which file types this package is able to deal with. It's like dividing your big project into a bunch of separate, smaller sub-tasks. This kind of thinking is exactly the practice of modular programming, and each subtask now can be termed as a module.
Each module should have an unique name, which in most cases is the the name of a Python file. This also leads to another programming concept, namespace . Let's put off explaining this concept for now.
Each module is nothing special but a Python file where your code snippets reside. The code snippet is filled with a large number of variables, functions as the code we've written.
It is highly likely that in two modules/files, there are two functions/variables that have coincidentally have the same name. (e..g, different modules are usually developed by different people in a team.) Okay, Here another problem arises. When people use our package, how could they know which function is from which module. Okay, the solution is to associate the function/variable name with the module name to get an unique identifier for each thing in our code.
In many occasions, packages and modules are used interchangeably. For example, you might have heard of that people saying I have a module that contains a bunch of sub-modules. Or, I have a package that contains many modules.
Still remember how to install packages through Anaconda Navigator or conda commands? Now let's learn how to bring modules into our script.
This is the simplest form for importing a module.
import math
math
Then how could we use functions inside a module? Hint: namespace.fun_name
a = 4
math.sqrt(a)
What if we do not want to load the whole module or how could we get rid of the namespace prefix?
from math import sqrt # now sqrt is added to the current namespace. Yes, your working file has also a namespace
sqrt(4)
Is it wonderful, isn't it? You can import a bunch of names at once, e.g., from math import sqrt, log2, log10
or you could use from module_name import *
, which imports all the variables/functions into your current namespace. (DANAGEROUS!!!!)
Then what is the namespace of the file I am working on?
__name__ #double underscores before and after
Why do we need to give it a alternative name or alias? It is because we want to give it an unique name in case my namespace has a funtion that has the same name as the imported function.
from math import sqrt as my_sqrt
my_sqrt(4)
from math import sqrt as my_sqrt, log2 as my_log2
a = my_sqrt(4)
b = my_log2(4)
print(a,b)