Is there a way to reference one function parameter from another function parameter in python?

Viewed 60

There may be a better way to do this, and if there is I'm all ears. But I am trying to write a function that takes a numpy array of arbitrary size and reduces it using Gauss-Jordan Elimination. I would like to create an augmented matrix with the passed matrix A on the left and either a default column vector of zeros or a user specified column vector on the right. In other words, for a matrix A and column vector b I could define my function like:

def gauss_jordan(A, b=np.zeros((A.shape[0],1)):
    # Do stuff here

Unfortunately, when I try to reference the first parameter A in the second parameter b it tells me it is not defined. Is there a way to reference the first passed parameter from the second parameter? Or is there a better way to do this?

EDIT: Doing as Tim suggested:

I get the following error when trying to pass a user defined vector b.

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

I had tried the true/false route before but ran into the same problem.

EDIT 2: Thanks all! I got it working properly with the following. The "is" operator slipped my mind. I added the reshape after the else so that it is returned as a column vector.

def gauss_jordan(A, b=None):
    rows, columns = A.shape
    
    if b is None:
        b = np.zeros((rows,1))
    else:
        b = b.reshape((rows,1))

    # Do other stuff
3 Answers

If you use b=None, it safest to do a b is None test:

In [47]: def foo(A, b=None):
    ...:     if b is None:
    ...:         b = np.zeros((A.shape[0],1))
    ...:     return b.shape
    ...: 
In [48]: foo(np.arange(3))
Out[48]: (3, 1)
In [49]: foo(np.arange(3),np.zeros(10))
Out[49]: (10,)

Not in this fashion, no. The default value is resolved when the function is defined. A has no bound value until the call, much later. In this case, your proper flow of data is as given in Tim's answer: provide an obviously "not supplied" value; test-and-set b as soon as you enter the function. This gives you the binding you want, consistent with Python language definition.

Here is a simple proof-of-concept:

def gj(A, b=None):
    b = b or len(A)
    print (A, b)

gj("Hello, world")
gj("Hello, world", 1729)

Output:

Hello, world 12
Hello, world 1729

Python does not support references to earlier function parameters in default value definitions. The Pythonic solution here is probably to use a default argument of None:

def gauss_jordan(A, b=None):
    if b is None:
        b = np.zeros((A.shape[0],1)
    # Do stuff here
Related