# variable length arguments demo
def someFunction(a, b, c, *varargs, **kwargs):
print('a = ', a)
print('b = ', b)
print('c = ', c)
print('*args = ', varargs)
print('type of args = ', type(varargs))
print('**kwargs = ', kwargs)
print('type of kwargs = ', type(kwargs))
# call someFunction with some arguments
someFunction(1, 'Apple', 4.5, 5, [2.5, 'b'], fname='Jake', num=1)
a = 1 b = Apple c = 4.5 *args = (5, [2.5, 'b']) type of args = <class 'tuple'> **kwargs = {'fname': 'Jake', 'num': 1} type of kwargs = <class 'dict'>
# regular function
def func(x): return x**2
print(func(4))
16
g = lambda x: x**2 # no name, no parenthesis, and no return keyword
# a function that takes x and returns x**2
print(g)
<function <lambda> at 0x7fc925e9dc80>
g(4)
16
https://composingprograms.com/pages/16-higher-order-functions.html
# computer summations of n natural numbers
# func is a function applied to all the natural numbers between 1 and n inclusive
def sum_naturals(func, n):
total, k = 0, 1
while k <= n:
total += func(k)
k += 1
return total
n = 100
print(f'sum of first {n} natural numbers = {sum_naturals(lambda x: x, n)}')
sum of first 100 natural numbers = 5050
# of course you can pass regular function
def even(n):
return n if n%2 == 0 else 0
print(f'sum of even numbers from 1 to {n} = {sum_naturals(even, n)}')
sum of even numbers from 1 to 100 = 2550
# sum of odd numbers from 1 to 100
print(f'sum of odd numbers from 1 to {n} = {sum_naturals(lambda x: x if x%2==1 else 0, n)}')
sum of odd numbers from 1 to 100 = 2500
# compute summations of n natural numbers
# by default sum_natural1 finds sum of all the natural numbers between 1 and n inclusive
def sum_naturals1(n, number_type="all"):
def even(x):
return x if x%2 == 0 else 0
def odd(x):
return x if x%2 == 1 else 0
def func(x):
# local function has access to global variables as well as parent frames
if number_type == 'even':
return x if x%2 == 0 else 0
else:
return x if x%2 == 1 else 0
total, k = 0, 1
while k <= n:
if number_type != 'all':
total += func(k)
#elif number_type == 'odd':
# total += odd(k)
else:
total += k
k += 1
return total
n = 100
print(f'sum of first {n} natural numbers = {sum_naturals1(n)}')
sum of first 100 natural numbers = 5050
print(f'sum of even numbers from 1 to {n} = {sum_naturals1(n, "even")}')
sum of even numbers from 1 to 100 = 2550
# sum of odd numbers from 1 to 100
print(f'sum of odd numbers from 1 to {n} = {sum_naturals1(n, "odd")}')
sum of odd numbers from 1 to 100 = 2500
def number_type(ntype='all'):
def even(x):
return x if x%2 == 0 else 0
def odd(x):
return x if x%2 == 1 else 0
def _(x): # function to return x as it is; any()
return x
if ntype == 'all':
return _
elif ntype == 'even':
return even
else:
return odd
n = 100
print(f'sum of first {n} natural numbers = {sum_naturals(number_type("all"), n)}')
sum of first 100 natural numbers = 5050
print(f'sum of even numbers from 1 to {n} = {sum_naturals(number_type("even"), n)}')
sum of even numbers from 1 to 100 = 2550
# sum of odd numbers from 1 to 100
print(f'sum of odd numbers from 1 to {n} = {sum_naturals(number_type("odd"), n)}')
sum of odd numbers from 1 to 100 = 2500
def curried_pow(x):
def g(y):
return pow(x, y)
return g
# same as 2**3
curried_pow(2)(3)
8
# let's create a list of integers and map each to a different value
nums = list(range(1, 11))
nums
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def my_map(alist, func):
for i in range(len(alist)):
alist[i] = func(alist[i])
my_map(nums, curried_pow(2))
nums
[2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
# a simple decorator example
# my_decorator decorates func
def my_decorator(func):
def wrapper():
print("Before the function is called...")
# call the original function
func()
print("After the function is called.")
return wrapper
def say_hello():
print("Hello there!")
# say_hello is decorated now, without modifying the original function
# just the behavior is modified by added extra print() before and after say_hello
say_hello = my_decorator(say_hello)
say_hello()
Before the function is called... Hello there! After the function is called.
# Python provides better syntax!
# use @decorting_function
@my_decorator
def say_hi():
print("Hi there!")
say_hi()
Before the function is called... Hi there! After the function is called.
# a simple count down function
def countDown(from_number):
if from_number <= 0:
print('Blast off!')
else:
print(from_number)
countDown(from_number-1)
# Doesn't slow down the countdown!
countDown(10)
10 9 8 7 6 5 4 3 2 1 Blast off!
# let's write a slow_down wrapper
import time
def slow_down(func):
"""Sleep 1 second before calling the function"""
def wrapper_slow_down(*args, **kwargs):
time.sleep(1) # sleep for a second
return func(*args, **kwargs) # call and return the result from the func
return wrapper_slow_down
countDownSlow = slow_down(countDown)
countDownSlow(10)
10 9 8 7 6 5 4 3 2 1 Blast off!