The problem
I have the following list in Python 3.6
Piko = {}
Piko['Name']='Luke'
I am trying to write a function that give the value of the element if it exist and is set and give None otherwise.
For example:
INPUT: isset(Piko['Name']) OUTPUT: Luke
INPUT: isset(Piko['Surname']) OUTPUT: None
What I have tried
1st try; based on my know how:
def isset1(x):
try:
x
except KeyError:
print(None)
else:
print(x)
2nd try; based on this answer:
def isset2(x):
try:
t=x
except IndexError:
print(None)
3rd try; based on this answer:
def isset3(x):
try:
x
except Exception:
print(None)
else:
print(x)
Any one of the previous gives me KeyError: 'Surname' error and does not output None as I wanted. Can anybody help me explaining how could I manage correctly the KeyError?
Piko.get('Surname')
Piko.get('Surname', None)
are identical and return None since "Surname" is not in your dictionary.
For future reference you can quickly discover this from the Python shell (eg ipython) by typing:
In[4]: help(Piku.get)
Which produces:
Help on built-in function get:
get(...)
D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
The exception is happening before it even gets into your isset function. When you do this:
isset(Piko['Name'])
… it's basically the same as doing this:
_tmp = Piko['Name']
isset(_tmp)
No matter what code you put inside isset, it's not going to help, because that function never gets called. The only place you can put the exception handling is one level up, in the function that calls isset.
Or, alternatively, you can not try to lookup dict[key] to pass into isset, and pass the dict and the key as separate parameters:
def isset(d, key):
try:
print(d[key])
except KeyError:
print(None)
But at this point, you're just duplicating dict.get in a clumsier way. You can do this:
def isset(d, key):
print(d.get(key, None))
… or just scrap isset and do this:
print(Piko.get('Name', None))
Or, since None is the default if you don't specify anything:
print(Piko.get('Name'))
Related
So recently, I learned something new which is Try and Except, and I still can't really get how it functions. Here is simple code of block. I would like some explanation on how this codes will run. Dish here refers to an item from dictionary. Note : Either ValueError or KeyError can be raised.
try:
return dish["name"].index(cost["$"])
except KeyError:
return None
let's assume you have two dictionaries:
dish = {"name": ["A", "B", "C", "D"]}
cost = {"$": "A"} # It should be any value in A,B,C,D else it will raise Value Error for dish["name"].index(cost["$"])
Now if you want to raise ValueError Then you should search the index of value that does not exist in the list in your case
if I try to do this:
# return dish["name"].index(cost["$"]) $ This will raise ValueError if
# cost['$']= "E" because "E" does not exist in dish["name"] list so it will raise value error
Let me know if it explains your use case.
Quick example but see https://docs.python.org/3/tutorial/errors.html for more info.
Your code will "try" and run the line
return dish["name"].index(cost["$"])
and if there is a ValueError then it will execute the code
return None
A ValueError is a mathematical error such as division by zero. If your code encounters a ValueError, it will run Return None, which does nothing. Try replacing return None with something like print("Exception") and force a value error to see what will happen.
I have this dict
dic = {'wow': 77, 'yy': 'gt', 'dwe': {'dwdw': {'fefe': 2006}}}
and I have this function
def get_missing_key(data, nest, default_value):
try:
return data + nest
except KeyError as err:
return default_value
and this is how I call it:
get_missing_key(dic, ['dwe']['dwdw']['fefe'], 16)
What I want is that I want the second parameter to get converted to normal python expression and do calculations with it
I want it to be like this
def get_missing_key(data, nest, default_value):
try:
return data['dwe']['dwdw']['fefe']
except KeyError as err:
return default_value
is there a way to achieve this?
But what I have clearly doesn't work, since I can't concatinate a dict with a list
You could use reduce like #kyle-parsons did, or you could manually loop:
lookup = ["dwe", "dwdw", "fefe"]
def find_missing(data, lookup, default):
found = data
for i in lookup:
try:
found = found[i]
except KeyError:
return default
return found
You should pass your keys as a list.
from functools import reduce
def get_missing_key(data, nest, default_value):
try:
reduce(dict.__getitem__, nest, data)
except KeyError:
return default_value
In general, Python eagerly evaluates expressions and there's no way to delay that short of passing in strings of code to be built up and execed, but that's really not a good idea.
I often have functions that return multiple outputs which are structured like so:
def f(vars):
...
if something_unexpected():
return None, None
...
# normal return
return value1, value2
In this case, there might be a infrequent problem that something_unexpected detects (say, a empty dataframe when the routine expects at least one row of data), and so I want to return a value to the caller that says to ignore the output and skip over it. If this were a single return function then returning None once would seem fine, but when I'm returning multiple values it seems sloppy to return multiple copies of None just so the caller has the right number of arguments to unpack.
What are some better ways of coding up this construct? Is simply having the caller use a try-except block and the function raising an exception the way to go, or is there another example of good practice to use here?
Edit: Of course I could return the pair of outputs into a single variable, but then I'd have to call the function like
results = f(inputs)
if results is None:
continue
varname1, varname2 = results[0], results[1]
rather than the more clean-seeming
varname1, varname2 = f(inputs)
if varname1 is None:
continue
Depends on where you want to handle this behavior, but exceptions are a pretty standard way to do this. Without exceptions, you could still return None, None:
a, b = f(inputs)
if None in (a, b):
print("Got something bad!")
continue
Though, I think it might be better to raise in your function and catch it instead:
def f():
if unexpected:
raise ValueError("Got empty values")
else:
return val1, val2
try:
a, b = f()
except ValueError:
print("bad behavior in f, skipping")
continue
The best practice is to raise an exception:
if something_unexpected():
raise ValueError("Something unexpected happened")
REFERENCES:
Explicit is better than implicit.
Errors should never pass silently.
Unless explicitly silenced.
PEP 20 -- The Zen of Python
I would like to assign some value a function returned if the value is not None to variable, or else assign different value, or yet another different value...
I only want to call the function once.
I currently use try and except TypeError, but only works for two options and is not very clean.
try:
value = someFunction()["content"]
except KeyError:
value = someOtherFunction()["content"]
Since the value returned is of type dict, you may use dict.get to achieve the same behavior in one-line as:
value = someFunction().get("content", someOtherFunction()["content"])
But this will be applicable if you are dealing with only two values as mentioned in the question. For dealing with chain of multiple functions, you may create a list of function and check for the "key" in the returned dict object as:
my_functions = [func1, func2, func3]
for func in my_functions:
returned_val = func()
if 'content' in returned_val: # checks for 'content' key in returned `dict`
value = returned_val['content']
break
Would something like this work?
def try_run(func_list, field, default_value):
for f in func_list:
try:
value = f()[field]
return value
except (TypeError, KeyError):
pass
return default_value
try_run([someFunction, someOtherFunction], 'content', 'no content')
Sample Code
This requires an external library but you could use iteration_utilities.first:
from iteration_utilities import first
# The logic that you want to execute for each function (it's the same for each function, right?)
def doesnt_error(func):
try:
return func()['content']
except (KeyError, TypeError):
return False
# some sample functions
func1 = lambda: None
func2 = lambda: {}
func3 = lambda: {'content': 'what?'}
# A tuple containing all functions that should be tested.
functions = (func1, func2, func3)
# Get the first result of the predicate function
# the `retpred`-argument ensures the function is only called once.
value = first(functions, pred=doesnt_error, retpred=True)
1 This is from a third-party library I have written: iteration_utilities.
If someFunction returns a dictionary, you can use
dict_object = someFunction()
if 'content' in dict_object.keys() and dict_object['content'] is not None:
value = dict_object['content']
else:
value = someOtherFunction['content']
value = someFunction()["content"] if ("content" in someFunction() and someFunction()["content"] != None) else someOtherFunction()["content"]
Although with this someFunction is going to be called potentially multiple times so you might want to add
d = someFunction()
before and replace someFunction() by d in the oneliner
I am always annoyed by this fact:
$ cat foo.py
def foo(flag):
if flag:
return (1,2)
else:
return None
first, second = foo(True)
first, second = foo(False)
$ python foo.py
Traceback (most recent call last):
File "foo.py", line 8, in <module>
first, second = foo(False)
TypeError: 'NoneType' object is not iterable
The fact is that in order to correctly unpack without troubles I have either to catch the TypeError or to have something like
values = foo(False)
if values is not None:
first, second = values
Which is kind of annoying. Is there a trick to improve this situation (e.g. to so set both first and second to None without having foo returning (None, None)) or a suggestion about the best design strategy for cases like the one I present ? *variables maybe ?
Well, you could do...
first,second = foo(True) or (None,None)
first,second = foo(False) or (None,None)
but as far as I know there's no simpler way to expand None to fill in the entirety of a tuple.
I don't see what is wrong with returning (None,None). It is much cleaner than the solutions suggested here which involve far more changes in your code.
It also doesn't make sense that you want None to automagically be split into 2 variables.
I think there is a problem of abstraction.
A function should maintain some level of abstraction, that helps in reducing complexity of the code.
In this case, either the function is not maintaining the right abstraction, either the caller is not respecting it.
The function could have been something like get_point2d(); in this case, the level of the abstraction is on the tuple, and therefore returning None would be a good way to signal some particular case (e.g. non-existing entity). The error in this case would be to expect two items, while actually the only thing you know is that the function returns one object (with information related to a 2d point).
But it could also have been something like get_two_values_from_db(); in this case the abstraction would be broken by returning None, because the function (as the name suggest) should return two values and not one!
Either way, the main goal of using a function - reducing complexity - is, at least partially, lost.
Note that this issue would not appear clearly with the original name; that's also why it is always important to give good names to function and methods.
I don't think there's a trick. You can simplify your calling code to:
values = foo(False)
if values:
first, second = values
or even:
values = foo(False)
first, second = values or (first_default, second_default)
where first_default and second_default are values you'd give to first and second as defaults.
How about this:
$ cat foo.py
def foo(flag):
if flag:
return (1,2)
else:
return (None,)*2
first, second = foo(True)
first, second = foo(False)
Edit: Just to be clear, the only change is to replace return None with return (None,)*2. I am extremely surprised that no one else has thought of this. (Or if they have, I would like to know why they didn't use it.)
You should be careful with the x or y style of solution. They work, but they're a bit broader than your original specification. Essentially, what if foo(True) returns an empty tuple ()? As long as you know that it's OK to treat that as (None, None), you're good with the solutions provided.
If this were a common scenario, I'd probably write a utility function like:
# needs a better name! :)
def to_tup(t):
return t if t is not None else (None, None)
first, second = to_tup(foo(True))
first, second = to_tup(foo(False))
def foo(flag):
return ((1,2) if flag else (None, None))
OK, I would just return (None, None), but as long as we are in whacko-land (heh), here is a way using a subclass of tuple. In the else case, you don't return None, but instead return an empty container, which seems to be in the spirit of things. The container's "iterator" unpacks None values when empty. Demonstrates the iterator protocol anyway...
Tested using v2.5.2:
class Tuple(tuple):
def __iter__(self):
if self:
# If Tuple has contents, return normal tuple iterator...
return super(Tuple, self).__iter__()
else:
# Else return a bogus iterator that returns None twice...
class Nonerizer(object):
def __init__(self):
self.x=0
def __iter__(self):
return self
def next(self):
if self.x < 2:
self.x += 1
return None
else:
raise StopIteration
return Nonerizer()
def foo(flag):
if flag:
return Tuple((1,2))
else:
return Tuple() # It's not None, but it's an empty container.
first, second = foo(True)
print first, second
first, second = foo(False)
print first, second
Output is the desired:
1 2
None None
Over 10 years later, if you want to use default values I don't think there is a better way than the one already provided:
first, second = foo(False) or (first_default, second_default)
However, if you want to skip the case when None is returned, starting from Python 3.8 you can use the walrus operator (ie. assignment expressions) - also note the simplified foo:
def foo(flag):
return (1, 2) if flag else None
if values := Foo(False):
(first, second) = values
You could use an else branch to assign default values that's worse than the previous or option.
Sadly, the walrus operator does not support unparenthesized tuples so it is just a one line gain compared to:
values = foo(False)
if values:
first, second = values
One mechanism you can use to avoid the problem entirely when you have control of the method foo is to change the prototype to allow giving a default. This works if you are wrapping state but can't guarantee that a particular tuple value exists.
# self.r is for example, a redis cache
# This method is like foo -
# it has trouble when you unpack a json serialized tuple
def __getitem__(self, key):
val = self.r.get(key)
if val is None:
return None
return json.loads(val)
# But this method allows the caller to
# specify their own default value whether it be
# (None, None) or an entire object
def get(self, key, default):
val = self.r.get(key)
if val is None:
return default
return json.loads(val)
I found a solution for this problem:
Return None or return an object.
However you don't want to have to write a class just to return an object. For this, you can use a named tuple
Like this:
from collections import namedtuple
def foo(flag):
if flag:
return None
else:
MyResult = namedtuple('MyResult',['a','b','c']
return MyResult._make([1,2,3])
And then:
result = foo(True) # result = True
result = foo(False) # result = MyResult(a=1, b=2, c=3)
And you have access to the results like this:
print result.a # 1
print result.b # 2
print result.c # 3