How to supply a default value iff a value is None? - python

Is there an operator or a library function such that v ??? d
evaluates to v if v is distinct from None and doesn't evaluate d, or
evaluates to d if v is equal to None.
(where by ??? I denote the operator I'm seeking).
Operator or is almost what I want, but it evaluates to the default value if v is False. I want the default only if the argument is None, so that False ??? d evaluates to False.
Update: To clarify, in my case v can be a complex expression, like computeSomethingLong() ??? d. So I can't use
computeSomethingLong() if computeSomethingLong() is not None else d
I'd have to do something like
tempvar = computeSomethingLong()
tempvar if tempvar is not None else d
which feels quite awkward, compared to computeSomethingLong() or d.
Update: The closest I got is to define my own function:
def orElse(v, deflt):
if v is not None:
v
else:
deflt
But the drawback is that deflt is always evaluated! I want it to evaluate only if it's actually needed. In particular, I want that in
firstLongComputation() ??? secondLongComputation()
the first computation is evaluated; if it's result is not None, it is returned. Otherwise the second one is evalauted (and only in this case) and it will be the result of the expression.

There's no such operator, but it's straigtforward anyway using ternary if "operator"
v if v is not None else d
If v is an expensive function call, you can employ any kind of caching (aka memoization) to still use the same approach:
#memoize
def computeSomethingLong():
"""whatever"""
computeSomethingLong() if computeSomethingLong() else computeSomethingElse()
Will still evaluate computeSomethingLong once.
See python manual or some other instructions for details on decorators.

Try with v if v is not None else d

Related

python convert a string to a logic gate function

I have a python string like: "(a and b and c) or (d and e)", where a, b, c, d and e are conditions of some kind. As you can probably see, this is actually a logical expression.
I'd like to somehow convert it into a logic-gate-like function, say, f. So I would pass a number of true conditions to f, and get the logical results. Examples:
If I pass it (d and e) (i.e., d and c are true), f returns True.
If I pass it (a and b and c), f returns True.
If I pass it just a, f returns False.
If I pass it just b and c, f returns False.
I have no idea how to tackle such a question. strtobool doesn't quite handle my requirements, and I'm not sure how to even convert the given string into a function. As for passing it true conditions as input, I'm thinking of passing it a list of True booleans, i.e. all conditions are False by default. e.g. from the first example above:
d = True; e = True
f([d, e])
> True
d = True; e = False
f([d])
> False
You're looking for eval.
Essentially, you can do-
eval('d and e', {'d': True, 'e': False})
Which passes the d and e string to evaluate, and also passes in some globals, to set the value of those variables.
It's often better to use the third argument, locals, instead of globals however.
eval('d and e', {}, {'d': True, 'e': False})
This will achieve the same thing, except d and e are set in local scope, the second argument is just empty.

Setting defaults for empty arguments (Python)

Let's say we have the function f and I need the argument b to default to an empty list, but can't set b=[] because of the issue around mutable default args.
Which of these is the most Pythonic, or is there a better way?
def f(a, b=None):
if not b:
b = []
pass
def f(a, b=None):
b = b or []
pass
The first form as it reads easier. Without any specific context, you should explicitly test for the default value, to avoid potential truthiness issues with the passed in value.
def f(a, b=None):
if b is None:
b = []
pass
From PEP 8, Programming Recommendations:
Also, beware of writing if x when you really mean if x is not None --
e.g. when testing whether a variable or argument that defaults to None
was set to some other value. The other value might have a type (such
as a container) that could be false in a boolean context!
You can see examples of this approach throughout the cpython repository:
Lib/bdb.py
Lib/argparse.py
Lib/base64.py
def f(a, b=''):
if not b:
b = []
print(a)
You can cdo something simple such as "if not b". If you are going to make the default argument an empty string or set it equal to None, you can simply use an if statement to define what B should be if you are never actually going to enter an argument for b. In this example we simply set it to an empty list.

How can a function return a dynamic value that depends on the number of receivers in Python?

I was trying to do a "strange" (but useful in my case) function that can return a dynamic list whose len depends on the amount of receiver.
For example:
f() returns a dynamic list of None, so I can do the following:
a = f() => a = None
a, b = f() => a=b= None
(a, b) = f() => a=b= None
(a, b, c, d, e, f) = f() => a=b=c=d=e=f= None
I think this might be done via generator comprehension or iterator, but I was blocked on how to get the amount of recevier. Maybe I was in the wrong direction. Would you advise me some tips?
Any helps will be appreciated.
Many Thank,
Tiezhen
This is not possible in Python. The function on the right hand site has no knowledge of the context it was called in. The right hand site is evaluated before any of the name bindings take place.
Unfortunately, Python unpacks returned tuples using the Pythonic "it's easier to ask forgiveness than permission" approach. That is, if you have a statement:
a,b,c = f()
Behind the scenes, it's doing something along the lines of:
try:
a = returned[0]
b = returned[1]
c = returned[2]
except IndexError:
raise ValueError('need more than k values to unpack')
try:
_ = returned[4]
except IndexError:
pass
else:
raise ValueError('too many values to unpack')
So it's discovering dynamically the number of values returned. Unfortunately, that precludes us from being clever and creating a new type for handling variable returns:
class VariableReturn(object):
def __getitem__(self, index):
return ...
In Python 3, you can sort of do what you're asking, but the burden is on the caller, not the function being called. The function should always return the same number of results, but we'll trap the remaining results using extended tuple unpacking, as shown in this StackOverflow question.
Using this approach, you can return as many results as you'd like, but you need to always return at least as many as you need in the maximal case. The rest get packed into a trailing tuple.
a,*others = f()
a,b,*others = f()
a,b,c,*others = f()
If you don't mind using Python 3, you can ignore what you don't need, for example:
a, b, c, d, *_ = (x for x in range(100))
Try this:
def f(n):
return (None, ) * n
For example:
a, b, c = f(3)
... That's about as far as you can get, since in Python there's no way to know how many variables are in the left-hand side of an assignment.
Can't be done.
Functions in Python return one value, only. While it may sometimes look like more, it's still just one value: a tuple. Multiple assignment is then a process of tuple unpacking.
Your question then can be restated: can we create an object that acts like a tuple of varying length, depending on how many values need to be unpacked? And that's simply not made available as an option.
Probably the closest I can think of is to use a generator and get the desired number of items with itertools.islice:
a = itertools.count()
x, y, z = itertools.islice(a, 3) # 0, 1, 2
u, v = itertools.islice(a, 2) # 3, 4
But that's pretty far from what was hoped for.
pretty not nice but perhaps this helps you:
def f(x):
for i in x:
globals()[i] = None
f(['a','b','c'])

Best way to do conditional assignment in python

I tend to use this a lot, but it's ugly:
a = (lambda x: x if x else y)(get_something())
So I wrote this function:
def either(val, alt):
if val:
return val
else:
return alt
So you can do:
a = either(get_something(), y)
Is there a built-in function for this (similar to ISNULL in T-SQL)?
The or operator does what you want:
get_something() or y
In fact, it's chainable, like COALESCE (and unlike ISNULL). The following expression evaluates to the left-most argument that converts to True.
A or B or C
Easy!
For more conditional code:
a = b if b else val
For your code:
a = get_something() if get_something() else val
With that you can do complex conditions like this:
a = get_something() if get_something()/2!=0 else val
You may use:
a = get_something() or y
If get_something is True in boolean context, its value will be assigned to a. Otherwise - y will be assigned to a.
You can use a simple or, like so:
>>> a = None
>>> b = 1
>>> c = (a or b) # parentheses are optional
>>> c
1
I have provided an answer to this question to another user. Check it out here:
Answer to similar question
To respond quickly here, do:
x = true_value if condition else false_value
I'm also using the (a,b)[condition based on the value of a] form, saving the result of the get_something() call into a, in the rare cases that are best presented here: http://mail.python.org/pipermail/python-list/2002-September/785515.html
...
a=0 b=None a or b => None (a,b)[a is None] => 0
a=() b=None a or b => None (a,b)[a is None] => ()
...

Pythonic way to select first variable that evaluates to True

I have some variables and I want to select the first one that evaluates to True, or else return a default value.
For instance I have a, b, and c. My existing code:
result = a if a else (b if b else (c if c else default))
Another approach I was considering:
result = ([v for v in (a, b, c) if v] + [default])[0]
But they both feel messy, so is there a more Pythonic way?
Did you mean returning first value for what bool(value)==True? Then you can just rely on the fact that boolean operators return last evaluated argument:
result = a or b or c or default
If one variable is not "defined", you can't access its name. So any reference to 'a' raises a NameError Exception.
In the other hand, if you have something like:
a = None
b = None
c = 3
you can do
default = 1
r = a or b or c or default
# r value is 3
So long as default evaluates to True:
result = next((x for x in (a, b, c, d , e, default) if x))
You could do something like this (in contrast to the other answers this is a solution where you don't have to define the 'missing' values as being either None or False):
b = 6
c = 8
def first_defined(items):
for x in items:
try:
return globals()[x]
break
except KeyError:
continue
print first_defined(["a", "b", "c"])
In order to avoid NameErrors when a, b or c isn't defined: give the function a list of strings instead of variable references (you can't pass non-existing references). If you are using variables outside the 'globals()' scope, you could use getattr with its default argument.
--
If a, b and c are defined, I'd go for something like this (considering the fact that an empty string, None or False evaluate to a boolean False):
a = None
b = 6
c = 8
def firstitem(items):
for x in items:
if x:
return x
break
else:
continue
print firstitem([a, b, c])
Don't know if this works in every case, but this works for this case.
a = False
b = "b"
c = False
default = "default"
print a or b or c or default # b
How about this ?
a=None
b=None
c=None
val= reduce(lambda x,y:x or y,(a,b,c,"default"))
print val
The above prints "default". If any of the inputs is defined, val would contain the first defined input.
If by defined you mean ever assigned any value whatsoever to in any scope accessible from here, then trying to access an "undefined" variable will raise a NameError exception (or some subclass thereof, but catching NameError will catch the subclass too). So, the simplest way to perform, literally, the absolutely weird task you ask about, is:
for varname in ('a', 'b', 'c'):
try: return eval(varname)
except NameError: pass
return default
Any alleged solution lacking a try/except won't work under the above meaning for "defined". Approaches based on exploring specific scopes will either miss other scopes, or be quite complex by trying to replicate the scope-ordering logic that eval does for you so simply.
If by "defined" you actually mean "assigned a value that evaluates to true (as opposed to false)", i.e., all values are actually defined (but might happen to be false, and you want the first true value instead), then the already-proposed a or b or c or default becomes the simplest approach. But that's a totally different (and even weirder!) meaning for the word "defined"!-)

Categories

Resources