16

I look up in a table if keys have associated arrays, or not. By design, my table.__getitem__() somtimes returns None rather than KeyError-s. I would like this value to be either None, or the numpy array associated with w.

value = table[w] or table[w.lower()]
# value should be a numpy array, or None
if value is not None:
    stack = np.vstack((stack, value))

Only if I go with the above code, and the first lookup is a match, I get :

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

and if I go with value = table[w].any() or table[w.lower()].any(), then if it's a mismatch, I expectedly bump into :

AttributeError: 'NoneType' object has no attribute 'any'

I must be missing the correct way to do this, how to do ?

Nikana Reklawyks
  • 3,233
  • 3
  • 33
  • 49
  • 1
    Obvious repost of [this other question](http://stackoverflow.com/questions/36783921), because the correct answer there doesn't satisfy my need. I'd want a shorter way than `if table[w] is not None: ... elif table[w.lower()] is not None: ... else`, if possible. – Nikana Reklawyks Sep 19 '16 at 07:20
  • @Goyo: `v = a or b` raises the `ValueError` if `a` is an array (not if `a` is `None` and `b` is an array though) – Nikana Reklawyks Sep 19 '16 at 07:29
  • a = None .... isinstance(a, (type(None))) # True .... if a is anything else, it will return false. Obviously only useful to branch between None and if you can guarantee that 'a' will be some incarnation of an array – NaN Sep 19 '16 at 07:40
  • @Nikana Your question is not clear. " I would like this value to be either `None`..." when do you want it to be None? "or the numpy array associated with `w`" What's the associated array? `table[w]`? `table[w.lower()]`? The errors you are getting are to be expected but I do not understand what you want to achieve. – Stop harming Monica Sep 19 '16 at 07:40
  • @Goyo: I want value to be None if table returns none on w, and none on w.lower(). Else, to be the first non-None value (so yes, ideally, table[w]). – Nikana Reklawyks Sep 19 '16 at 07:42

4 Answers4

14
if type(value) is numpy.ndarray:
    #do numpy things
else
    # Handle None

Though the above would work, I would suggest to keep signatures simple and consistent, ie table[w] should always return numpy array. In case of None, return empty array.

Ayan Guha
  • 750
  • 3
  • 10
8

The question is answered, but other folks who encounter this error may want a general solution. With the idea of being explicit in mind we can use the function isinstance. Here is a working example.

import numpy as np

a = np.array([1,2,3])
b = None
for itm in [a,b]:
    isinstance(itm,np.ndarray)

So in the context of the question

value = table[w]
if not isinstance(value,np.ndarray):
    value = table[w.lower()]
ajrichards
  • 259
  • 2
  • 5
  • Sorry but this has very little to do with the question. The question is about the `value = ???` part. – Nikana Reklawyks Dec 24 '18 at 21:33
  • This is the same answer as your accepted answer just more explicit. The problem is that you cannot check to see if an array == None (the error you observed). But you can use the is instance that I showed above. I edited the above comment. – ajrichards Dec 26 '18 at 20:59
  • I can very much check if `value == None`, that's what the accepted answer does. What I would have loved is a one liner that assigns the first non-None value out of `[table[w], table[w.lower()]]` if any, or else None. The accepted answer does that perfectly, in 3 lines. I don't understand your contribution. – Nikana Reklawyks Dec 30 '18 at 09:25
  • using `is` works in this case, but using == throws the ValueError you saw above. Good Python code is explicit. I am showing you how to test if value is an array not if it is None... which is better Python code. I refer you to the Zen of Python if this is still hard to understand. – ajrichards Dec 31 '18 at 20:10
4

IIUC this should work:

value = table[w]
if value is None:
    value = table[w.lower()]
Stop harming Monica
  • 12,141
  • 1
  • 36
  • 56
2

Use dict.get.

Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.

value = table.get(w, table.get(w.lower()))

So if table[w] is not there you will get table[w.lower()] and if that's not there you'll get None.

Sevanteri
  • 3,749
  • 1
  • 23
  • 27
  • Ooh, interesting. Though... what happens if the default value is None, does it fail, or accept that ? And why would it default to the default if the first does return something, i.e. None ? – Nikana Reklawyks Sep 19 '16 at 07:50
  • 2
    @NikanaReklawyks Every function in Python implicitly returns `None` if nothing else is specified: the default value is what is assigned if the first returns `None` – TemporalWolf Sep 19 '16 at 07:52
  • Note that OP mentioned that their `__getitem__` implementation won't always raise a `KeyError`. Also `table.get(w.lower())` won't be lazily evaluated. – swenzel Sep 19 '16 at 08:02
  • 1
    OP says it **sometimes** returns `None` instead of `KeyError` so I assumed `table` is just a normal `dict` filled with numpy arrays and `None`s. But good point on the laziness. – Sevanteri Sep 19 '16 at 08:06