Python functions

Anh-Thi Dinh

Facts

  • In python, function is the first-class object. It's can be used as an argument.
  • Function can be used as a return value.
    • return func1: reference to func1.
    • return func1(): results of evaluating func().
  • Should we check the argument/input?: No! The responsibility is on the caller! Your function should be well-documented, that's it! (ref)

Create a normal function

If a function doesn't return any value, it returns None.
1# without arguments
2def func_name():
3  pass
1# with arguments
2def func_name(<args>):
3  pass
1# return
2def func_name(<args>):
3  return <some_thing>
1# call a function
2func_name(<args>)

Unpacking a function

1def sum_and_div(num1, num2):
2  sum_nums = num1 + num2
3  div_nums = num1 / num2
4  return sum_nums, div_nums # multiple returns
5
6sum, div = sum_and_div(18, 9)
7print(sum, div)
1# output
227 2.0

Functions with stars (args and *kwargs)

The *args will give you all function parameters as a tuple: (ref)
1def foo(*args):
2  print(args)
3  for a in args:
4    print(a)
5
6foo(1)
7foo(2, 3, 4)
1# output
2(1,)
31
4(2, 3, 4)
52
63
74
1def foo(rarg1, rarg2):
2  print(rarg1, rarg2)
3
4lst = [1, 2]
5foo(*lst)
6tpl = (3, 4)
7foo(*tpl)
1# output
21 2
33 4
4
If you wanna use "keywords arguments", use **args:
1def kwfunc(**kwargs):
2  print(type(kwargs))
3  print(kwargs)
4
5kwfunc()
6kwfunc(kw1="thi", kw2="dinh")
1# output
2<class 'dict'>
3{}
4<class 'dict'>
5{'kw1': 'thi', 'kw2': 'dinh'}
Use a dictionary as an input,
1def kwfunc(**kwargs): # must have **
2  print(kwargs)
3
4kwargs = {'kw1': "thi", 'kw2': "dinh"}
5kwfunc(**kwargs) # must have **
6
1# output
2{'kw1': 'thi', 'kw2': 'dinh'}
1def kwfunc(kw1="john", kw2="doe"):
2  print(kw1, kw2)
3
4kwargs = {'kw1': "thi", 'kw2': "dinh"}
5
6kwfunc()
7kwfunc(kwargs) # goes to kw1
8kwfunc(**kwargs) # goes to both kw1 & kw2
9
1# output
2john doe
3{'kw1': 'thi', 'kw2': 'dinh'} doe
4thi dinh
 
Coupling rargs, *args and **kwargs:
  • Required positional arguments: rarg1, rarg2, ...
  • Optional positional arguments: args.
  • Optional key-values arguments: *kwargs.
1def kwfunc(rarg1=0, rarg2=0, *args, **kwargs):
2  print("required args: ", rarg1, rarg2)
3  if args:
4    print("*args: ", args)
5  if kwargs:
6    print("**kwargs: ", kwargs)
7  print("\\n")
8
9
10kwfunc()
11kwfunc(1, 2)
12kwfunc(3, 4, 5, 6)
13kwfunc(kw1="thi", kw2="dinh")
1# output
2required args:  0 0
3
4required args:  1 2
5
6required args:  3 4
7*args:  (5, 6)
8
9required args:  0 0
10**kwargs:  {'kw1': 'thi', 'kw2': 'dinh'}
All arguments after * must be key-value arguments,
1def func(rarg1, rarg2, *, kwarg1, kwarg2):
2  print("required args: ", rarg1, rarg2)
3  print("kwarg*: ", kwarg1, kwarg2)
4
5# func(1, 2, 3, 4) # error!
6func(1, 2, kwarg1=3, kwarg2=4)
1# output
2required args:  1 2
3kwarg*:  3 4

Lambda function

It's convenient but don't use it regularly, use def (in 1 line) instead.
1x = lambda a : a + 10
2print(x(5))
3
4# you can use this
5def x(a): return a + 10
1# output
215
1# if else with lambda function
2lambda row: 'good' if (row>=80) else ('bad' if row<80 else '')

Check input & raise error

Something like that,
1if par1 is None:
2  msg = "par1 must be in type `int`"
3  raise TypeError(msg)
You can check other exceptions here.

Decorators

1def my_decorator(func):
2    def wrapper():
3        print("Before func called.")
4        func()
5        print("After func called.")
6    return wrapper
7
8def say_whee():
9    print("Whee!")
10
11say_whee = my_decorator(say_whee)
12say_whee()
1# output
2Before func called.
3Whee!
4After func called.
In a class (note that, there is no self parameter in _deco),
1class test_class():
2
3    def _deco(func):
4        def wrapper(self, name):
5            print('Before func called')
6            func(self, name)
7            print('After func called.')
8        return wrapper
9
10    @_deco
11    def fit(self, name):
12        print('Hello, ', name)
13
14a = test_class()
15a.fit('thi')
1# output
2Before func called
3Hello,  thi
4After func called