args and tuple expansion

In [6]:
import numpy as np
from scipy.integrate import quad
  • Functions like fsolve, quad and others have an argument called args that you can set to have those functions pass extra arguments to the function provide.
  • But fsolve and quad (etc.) don't know how many arguments there are, and there could be an arbitrary number.
  • Tuple expansion to the rescue!

Example 1

  • Below, function f can take any number of arguments.
  • args is a tuple, and the * part of *args can be thought of as collapsing the provided list of arguments into the tuple args.
    • The name args doesn't matter. It can be anything.
  • You can then loop over the elements of args.
In [7]:
def f(*args):
    print(args)        # args is a tuple
    for a in args:     # loop over elements of args
        print(a)
    
f(1.1, 2.2, 3.3)       # call the func with multiple arguments
(1.1, 2.2, 3.3)
1.1
2.2
3.3

Example 2

  • Below, function f takes three arguments.
  • When calling the function, we first make a tuple with three elements,
  • Then we expand the tuple into values using *xyz.
    • The * part of *xyz acts to expand the tuple into elements that are then placed in the individual arguments that the function takes.
In [12]:
def f(x,y,z):
    print(x)
    print(y)
    print(z)
    
xyz = (1.1, 2.2, 3.3)
f(*xyz)
1.1
2.2
3.3

Example 3

  • Write your own version of quad that uses the trapazoid method, and passes in extra arguments that my function will need.
  • See the line fx = f(x, *args) where the tuple of args I pass in to myQuad is expanded into the coefficients c0, c1, and c2 of my quadratic function, defined below.

Trapazoid method: $$I = \Delta x\sum_{i=0}^n f_i - \frac{\Delta x}{2}(f_0-f_n)$$

Do the following integral: \begin{align} &I = \int_0^2f(x,c0,c1,c2)dx,\\ &\phantom{xxxxxxx}f(x,c_0,c_1,c_2) = c_2x^2 + c_1x + c_0. \end{align}

In [ ]:
def myQuad(f, a, b, n=100, args=None):
    x = np.linspace(a,b,n)
    Δx = x[1]-x[0]
    if args is None:
        fx = f(x)
    else:
        fx = f(x, *args)
        
    I = Δx*np.sum(fx) - Δx/2*(fx[0] + fx[-1])
    
    return I
    
#---------------

def f(x, c0, c1, c2):
    return c2*x**2 + c1*x + c0

#---------------

I = myQuad(f, 0, 2, args=(1.1, 2.2, 3.3))
print(I)

kwargs

  • Can use keyword arguments directly.
  • Order doesn't matter
  • Pass a dictionary using names and values
  • Expand with a double star: **
In [1]:
def f(x,y,z):
    print(x)
    print(y)
    print(z)

#------------ args:

args = (1.1, 2.2, 3.3)
f(*args)

print()

#------------ kwargs:
kwargs = {'z':3.3, 'x':1.1, 'y':2.2}   # notice the order
f(**kwargs)
1.1
2.2
3.3

1.1
2.2
3.3
In [9]:
def f(**kwargs):
    for k,v in kwargs.items():
        print(k,v)

f(param1=1.1, param2=2.2, param3=3.3)
param1 1.1
param2 2.2
param3 3.3

call order

  • If using formal (usual) arguments (fargs), args, and kwargs, use this order:
    f(fargs, *args, **kwargs)
In [ ]: