-1

I have a Python function that I would like to guarantee has been fed a variable, list, tuple, or Numpy array or matrix that consists only of a single number: 2,(2),[2], etc. If the function has been passed a tuple, list, array, etc. that consists of more than one value I would like it to raise an error or exception. The function would look something like this:

def f(x):
   #check if x is a single variable
   if(x.shape != (1)):
      #Error or exception and quit
   else:
      #keep working

However, when I run (for example) f(2) I am told that 'int' object has no attribute 'shape'. I am trying to figure out the correct way to do what I describe above in general sense, so that whether x is a variable, tuple, list, whatever the function can recognize whether it has a single variable or not.

NeutronStar
  • 2,057
  • 7
  • 31
  • 49
  • See: [How to know if an object has an attribute in Python](http://stackoverflow.com/questions/610883/how-to-know-if-an-object-has-an-attribute-in-python). i.e. `hasattr(x, 'shape')` – Mr. Polywhirl Nov 03 '14 at 22:54
  • 2
    For a one-element array of numpy the `.shape` is `(1,)`, not `(1)` – 6502 Nov 03 '14 at 22:54
  • can't you make sure that the input it receives is narrowed down at least somewhat at the source? Otherwise you'll just need to add a bunch of if/else statements checking its `type` and `len` respectively. (e.g. a normal list doesn't have a shape either) – Martin B. Nov 03 '14 at 22:55
  • in your particular example, shape is a method from x. This is because you are assuming that x is a numpy object. Insted of that, you have to use general methods. If you change, for instance x.shape as np.shape(x), it will work. Hope this helps. – Alejandro Nov 03 '14 at 22:56
  • Calling this "a single variable" is pretty misleading. An array value or list value can be stored in a single variable, exactly the same way an integer can. – abarnert Nov 03 '14 at 23:03
  • you can use `len` and `isinstance` – Hackaholic Nov 03 '14 at 23:25
  • @abarnert, if `x` is a single element list or array I want it to go through the function just fine. – NeutronStar Nov 04 '14 at 01:24

1 Answers1

1

If you want to use shape, you either need to wrap it in try/except, or type-check first. (The former is usually better.)

Also, note that (1) is not a 1-element tuple, it's just the number 1. Tuples are made by commas, not by parentheses.

But there's a bigger problem here: shape doesn't exist on lists, tuples, or other collections, only on NumPy arrays. So, you'll need a second fallback to deal with them. You could use the built-in len function, which works on all sized containers, or you could use np.shape, which works on all containers that NumPy knows how to convert to arrays (while everything else will end up as a single-element scalar of dtype object, so its shape will be ()). I'm not sure which is appropriate in this case. (One question to help decide the answer: does a 10-element dict count as having length 10, or 0?)

Maybe something like this:

def f(x):
    try:
        if x.shape != (1,):
            # Error or exception
    except AttributeError:
        try:
            if len(x) != 1:
                # Error or exception
        except TypeError:
            pass

However, note that strings have a size—a string is an iterable over its individual characters—and yet, often, you want to treat them as singular values.

More generally, an API that can take either a single value or a collection of values is usually a sign of something wrong with the design elsewhere in the program. Why aren't you generating single-value collections in the first place? Sometimes there's no way around this, because you're accepting values from someone else's code, or directly from the end-user—but make sure that's really true before going out of your way to overcomplicate things.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • The code you wrote, as far as I can tell, does what I want it. I am not familiar with dictionaries, so I cannot answer that question. The reason why I am not generating single-value collections in the first place is because I am accepting input from an end-user. – NeutronStar Nov 04 '14 at 01:39
  • @Joshua: But what format are you accepting it in? Unless you're calling `eval` on Python code entered by a user or something, there has to be some interface that you can define. Anyway, if you don't know enough to care about about `len(x)` or `np.shape(x)`, I guess just pick one at random and use it until you have a problem? – abarnert Nov 04 '14 at 01:43