2

I wonder if anyone has an elegant solution to being able to pass a python list, a numpy vector (shape(n,)) or a numpy vector (shape(n,1)) to a function. The idea would be to generalize a function such that any of the three would be valid without adding complexity.

Initial thoughts:

1) Use a type checking decorator function and cast to a standard representation.
2) Add type checking logic inline (significantly less ideal than #1).
3) ?

I do not generally use python builtin array types, but suspect a solution to this question would also support those.

5
  • You realise you can just do it? Python is dynamically typed, you don't have to specify parameter types. Commented Jul 7, 2014 at 20:04
  • sounds to me you answered your own question: yes, option 1 Commented Jul 7, 2014 at 20:04
  • Since all of the types support iterating and getting items by index, I would just use Duck typing. You can simply treat it as a list. Commented Jul 7, 2014 at 20:07
  • @Wolph if he uses numpy arrays, then he most likely wants to avoid explicitly iterating over the arrays Commented Jul 7, 2014 at 20:09
  • @shx2, I suppose your right. In that case I would like to quote Knuth: "Premature optimization is the root of all evil (or at least most of it) in programming.". If he still needs it, indeed... option 1. Commented Jul 7, 2014 at 20:12

2 Answers 2

3

I think the simplest thing to do is to start off your function with numpy.atleast_2d. Then, all 3 of your possibilities will be converted to the x.shape == (n, 1) case, and you can use that to simplify your function.

For example,

def sum(x):
    x = np.atleast_2d(x)
    return np.dot(x, np.ones((x.shape[0], 1)))

atleast_2d returns a view on that array, so there won't be much overhead if you pass in something that's already an ndarray. However, if you plan to modify x and therefore want to make a copy instead, you can do x = np.atleast_2d(np.array(x)).

Sign up to request clarification or add additional context in comments.

1 Comment

This works, but it is messy in the case of many functions - quite a bit of code duplication that a decorator avoids.
2

You can convert the three types to a "canonical" type, which is a 1dim array, using:

arr = np.asarray(arr).ravel()

Put in a decorator:

import numpy as np
import functools

def takes_1dim_array(func):
    @functools.wraps(func)
    def f(arr, *a, **kw):
        arr = np.asarray(arr).ravel()
        return func(arr, *a, **kw)
    return f

Then:

@takes_1dim_arr
def func(arr):
   print arr.shape

1 Comment

very nice. Spot on re: not wanting to iterate as well. I was leaning in the decorator direction, but did not want to miss a trivial solutions with something that I convinced myself was clean.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.