Reputation: 7486
Just of curiosity I'm trying to detect None-Scalar and None-tuple with short-code to use in lambda ... i.e. using isinstance is cumbersome.
So possible values are :
None
(None, 0)
Value
(Value, 1)
so far not (not x or not x[0])
, works for the cases 1,2,4, but not the 3rd
xx = lambda x: not( not x or not x[0] )
xx(None) => False
xx((None,0)) => False
xx(5)
TypeError: 'int' object has no attribute '__getitem__'
Upvotes: 2
Views: 169
Reputation: 11681
You'll want some form of is not None
to distinguish None
from a 0
value.
There's really no way to distinguish a pair from a number by coercing to a boolean. The non-empty tuples will always be truthy, the None will always be falsy, but the number could be either true or false (when 0).
You can do it in one line without using isinstance()
by using type()
instead:
lambda x: {tuple: x}.get(type(x), [x])[0] is not None
# or
lambda x: (x[0] if type(x) is tuple else x) is not None
The advantage of isinstance()
is that it works with subclasses.
Or with a standard library import:
from unittest.mock import ANY
lambda x: x not in [None, (None, ANY)]
This kind of thing is easy in languages that have pattern matching. (Which Python might be getting soon, see PEP 622.) I'm (ab)using the ANY
mock to achieve a similar effect.
Be careful with ANY
. It works by overriding .__eq__()
and .__ne__()
, so it's not necessarily reflexive.
Upvotes: 2
Reputation: 51683
Using truthy-testing for that is dangerous because it misfires for
'' # empty string
0 # integer zero
[] # empty list
False # boolean False
set() # empty other iterable
dict()
# etc.
because they all are Falsy - like None
.
# Problem:
xx(0) # False
xx( ([],42) ) # False
See pythong.org truth value testing
Create a function and use it instead/inside your lambda:
data = [None, (None, 0), "g", ("g", 1), 0, ([],42)]
def test(thing):
"""Returns 'False' for None and iterable inputs that have
None as first value."""
if thing is None:
return False
try:
a, *b = thing
if a is None:
return False
except: # purposefully not catching specific
pass
return True
for d in data:
print(d, test(d))
Output:
None False
(None, 0) False
g True
('g', 1) True
0 True
([], 42) True
Upvotes: 0