Function
Pass by reference
# pass by reference
def f2(m, im):
print('----------------Inside function-------------')
print(id(m), m) # 13977378998840, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(id(im), im) # 38097024, 10
m.append(100);
im = 100;
print(id(m), m) # 13977378998840, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 100]
print(id(im), im) # 38098848, 100
print('---------------Leave function--------------')
a = 10; # 38097024 10
b = list(range(10)) # 13977378998840, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9,]
print(id(a), a)
print(id(b), b)
f2(b, a);
print(id(a), a) # 38097024, 10
print(id(b), b) # 13977378998840, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 100]
- All parameters (arguments) in the Python language are passed by reference
- Mutable parameters, can be modified by function
- Immutable parameters, cannot be modified by function
Default arguments
# default arguments
def f1(p1, p2 = 10):
print(p1, p2)
f1(1)
Keyword arguments
# keyword arguments
def f3(p1 = 1, p2 = 2):
print(p1, p2)
f3(p2 = 10)
Variable-length arguments
# variabel-length arguments
def f4(*vartuple):
print('Lenght: ', len(vartuple))
print(type(vartuple), vartuple) # vartuple is a tuple
for i in vartuple:
print(i)
f4(1, 2, 3, 'end')
* in Function Calls
expands list or tuple into separate elements
#!/usr/bin/python
def f(a, b):
print(a, b)
l = [10, 20]; # singularize list or tuple
f(*l); # 10 20
Arbitary Key Parameters
pass parameters and their values as a dict to function
#!/usr/bin/python
def f(**args):
print(args)
for k in args.keys():
print(k, args[k])
f(inFile = 'input', outFile = 'output');
** in Function Calls
pass keyworded variables as a dict to function
#!/usr/bin/python
def f(**args):
print(args)
for k in args.keys():
print(k, args[k])
d = {'inFile':'input', 'outFile':'output'}; # singularize dict
f(**d);
Lambda
#!/usr/bin/python
#lambda
sum = lambda arg1, arg2: arg1+arg2;
print(sum(10, 20)) #30
#map
def t(arg):
return arg*10;
l = [1, 2, 3, 4];
r = map(t, l) #[10, 20, 30, 40], use function
print(list(r))
r = map(lambda x: x*10, l) #[10, 20, 30, 40], using lambda
print(list(r))
#filter
r = filter(lambda x: x%2 == 0, l) #[2, 4]
print(list(r))
from functools import reduce
#reduce
r = reduce(lambda x, y: x+y, l) #10
print(r)
Return
return multiple values, which are saved in a tuple
#!/usr/bin/python
def getNums():
return 1, 2
a, b = getNums()
print(a, b) # 1, 2
_, b = getNums() # use _ to hold a place
print(b) # 2
t = getNums()
print(t) # (1, 2), t is a tuple
#!/usr/bin/python
def getNum_1():
return 1 # return an integer
def getNum_2():
return # return nothing
def getNum_3():
return None # return None
def getNum_4():
pass # no return will return None
def main():
if getNum_1() is None:
print(getNum_1()) # not print
if getNum_2() is None:
print(getNum_2()) # None
if getNum_3() is None:
print(getNum_3()) # None
if getNum_4() is None:
print(getNum_4()) # None
if __name__ == '__main__':
main()
Recursive
#!/usr/bin/python
# recursive
def fib(n):
''' Doc String
Args:
n (int), integer number
Return:
int, fib number
'''
if n <= 1:
return 1
else:
return n*fib(n-1)
print(fib(10))
Functools
functools.partial, is used for partial function application which “freezes” some portion of a function’s arguments and/or keywords resulting in a new object with a simplified signature
#!/usr/bin/python
from functools import partial
def f(a, b):
print(a, b)
p = partial(f, b = 10)
p(1) # 1 10, pass 1 to a, p() only need one argument
functools.update_wrapper, to allow access to the original function for introspection and other purposes
#!/usr/bin/python
from functools import partial, update_wrapper
def f(a, b):
""" Docstring for f ..."""
print(a, b)
p = partial(f, b = 10)
p(1) # 1 10, pass 1 to a, p() only need one argument
#print(p.__doc__, p.__name__) # partial object does not have __name__ or __doc__ attributes by default
update_wrapper(p, f) # copies or adds attributes from the original function to the partial object
print(p.__doc__, p.__name__)
functools.partialmethod, returns a callable ready to be used as an unbound method of an object
#!/usr/bin/python
from functools import partialmethod
def getInfo(self, a, b):
"""a partial function in class"""
print(' called standalone with:', (self, a, b))
if self is not None:
print(' self.attr =', self.attr)
class MyClass:
"Demonstration class for functools"
def __init__(self):
self.attr = 'instance attribute'
method = partialmethod(getInfo, b = 10)
c = MyClass()
c.method(1)
functools.wraps, updating the properties of a wrapped callable when used in a decorator
#!/usr/bin/python
# use decorator
def d(f):
def decorated(a=10, b=100):
return f(a, b=b)
return decorated
@d
def f(a, b):
""" Docstring for f ..."""
print(a, b)
dwrapper = d(f)
dwrapper() # 10 100
print(dwrapper.__doc__, dwrapper.__name__) # None decorated
f(b = 1) # 10 1
#!/usr/bin/python
# use wraps() to define a decorator
from functools import wraps
def d(f):
@wraps(f)
def decorated(a=10, b=100):
return f(a, b=b)
return decorated
def f(a, b):
""" Docstring for f ..."""
print(a, b)
dwrapper = d(f)
dwrapper() # 10 100
print(dwrapper.__doc__, dwrapper.__name__) # Docstring for f ... f
functools.lru_cache, wraps a function in a least-recently-used cache, subsequent calls with the same arguments will fetch the value from the cache instead of calling the function
#!/usr/bin/python
from functools import lru_cache
@lru_cache()
def f(a, b):
print('%d, %d' % (a, b))
return a * b
f(1, 10)
print(f.cache_info()) # print out the cache information
f.cache_clear() # clear cache
Overload
Python does not have real function overload, either use overloading module or isinstance to check and handle different type of inputs
#!/usr/bin/python
def info(m):
if isinstance(m, str):
return 'Str: '+m
elif isinstance(m, int):
return 'Int: '+str(m)
else:
raise TypeError('Take str or int types ...')
print(info(100))
print(info('Hello'))
print(info(3.14)) # raise error
#!/usr/bin/python
# use default value to work as overloaded function
def info(a, b = None):
if b is None:
return a
return a+b
print(info(1, 2)) # 3
print(info(1)) # 1
Reference