Turning if statement into a single line while setting a variable [duplicate] - python-3.x

I need a way to get a dictionary value if its key exists, or simply return None, if it does not.
However, Python raises a KeyError exception if you search for a key that does not exist. I know that I can check for the key, but I am looking for something more explicit. Is there a way to just return None if the key does not exist?

You can use dict.get()
value = d.get(key)
which will return None if key is not in d. You can also provide a different default value that will be returned instead of None:
value = d.get(key, "empty")

Wonder no more. It's built into the language.
>>> help(dict)
Help on class dict in module builtins:
class dict(object)
| dict() -> new empty dictionary
| dict(mapping) -> new dictionary initialized from a mapping object's
| (key, value) pairs
...
|
| get(...)
| D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
|
...

Use dict.get
Returns 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.

You should use the get() method from the dict class
d = {}
r = d.get('missing_key', None)
This will result in r == None. If the key isn't found in the dictionary, the get function returns the second argument.

If you want a more transparent solution, you can subclass dict to get this behavior:
class NoneDict(dict):
def __getitem__(self, key):
return dict.get(self, key)
>>> foo = NoneDict([(1,"asdf"), (2,"qwerty")])
>>> foo[1]
'asdf'
>>> foo[2]
'qwerty'
>>> foo[3] is None
True

I usually use a defaultdict for situations like this. You supply a factory method that takes no arguments and creates a value when it sees a new key. It's more useful when you want to return something like an empty list on new keys (see the examples).
from collections import defaultdict
d = defaultdict(lambda: None)
print d['new_key'] # prints 'None'

A one line solution would be:
item['key'] if 'key' in item else None
This is useful when trying to add dictionary values to a new list and want to provide a default:
eg.
row = [item['key'] if 'key' in item else 'default_value']

As others have said above, you can use get().
But to check for a key, you can also do:
d = {}
if 'keyname' in d:
# d['keyname'] exists
pass
else:
# d['keyname'] does not exist
pass

You could use a dict object's get() method, as others have already suggested. Alternatively, depending on exactly what you're doing, you might be able use a try/except suite like this:
try:
<to do something with d[key]>
except KeyError:
<deal with it not being there>
Which is considered to be a very "Pythonic" approach to handling the case.

For those using the dict.get technique for nested dictionaries, instead of explicitly checking for every level of the dictionary, or extending the dict class, you can set the default return value to an empty dictionary except for the out-most level. Here's an example:
my_dict = {'level_1': {
'level_2': {
'level_3': 'more_data'
}
}
}
result = my_dict.get('level_1', {}).get('level_2', {}).get('level_3')
# result -> 'more_data'
none_result = my_dict.get('level_1', {}).get('what_level', {}).get('level_3')
# none_result -> None
WARNING: Please note that this technique only works if the expected key's value is a dictionary. If the key what_level did exist in the dictionary but its value was a string or integer etc., then it would've raised an AttributeError.

I was thrown aback by what was possible in python2 vs python3. I will answer it based on what I ended up doing for python3. My objective was simple: check if a json response in dictionary format gave an error or not. My dictionary is called "token" and my key that I am looking for is "error". I am looking for key "error" and if it was not there setting it to value of None, then checking is the value is None, if so proceed with my code. An else statement would handle if I do have the key "error".
if ((token.get('error', None)) is None):
do something

You can use try-except block
try:
value = dict['keyname']
except IndexError:
value = None

d1={"One":1,"Two":2,"Three":3}
d1.get("Four")
If you will run this code there will be no 'Keyerror' which means you can use 'dict.get()' to avoid error and execute your code

If you have a more complex requirement that equates to a cache, this class might come in handy:
class Cache(dict):
""" Provide a dictionary based cache
Pass a function to the constructor that accepts a key and returns
a value. This function will be called exactly once for any key
required of the cache.
"""
def __init__(self, fn):
super()
self._fn = fn
def __getitem__(self, key):
try:
return super().__getitem__(key)
except KeyError:
value = self[key] = self._fn(key)
return value
The constructor takes a function that is called with the key and should return the value for the dictionary. This value is then stored and retrieved from the dictionary next time. Use it like this...
def get_from_database(name):
# Do expensive thing to retrieve the value from somewhere
return value
answer = Cache(get_from_database)
x = answer(42) # Gets the value from the database
x = answer(42) # Gets the value directly from the dictionary

If you can do it with False, then, there's also the hasattr built-in funtion:
e=dict()
hasattr(e, 'message'):
>>> False

Related

Python3: Is it possible to use a variable as part of a function call

I am iterating through a list and want to use the list item to call a function. This is what I have tried:
def get_list1():
....do something
def get_list2():
....do something
def get_list3():
....do something
data = ['list1', 'list2', 'list3']
for list_item in data:
function_call = 'get_' + list_item
function_call()
But I am receiving the error "TypeError: 'str' object is not callable"
There are a couple of other ways that I could attack this, but this would be helpful to know for the future as well. Thanks!
Hopefully that TypeError is not surprising, because when you write...
function_call = 'get_' + list_item
...you're creating a string. If you want to look up a function by that name, you can use the vars() function, like this:
def get_list1():
print('list1')
def get_list2():
print('list2')
def get_list3():
print('list3')
data = ['list1', 'list2', 'list3']
for list_item in data:
function_call = 'get_' + list_item
fn = vars()[function_call]
fn()
Running the above produces:
list1
list2
list3
But as #pynchia notes in a comment on another answer, this isn't a great way to structure your code: you're better off building an explicit dictionary mapping names to functions if you really need this sort of functionality. Without seeing your actual code it's hard to tell what the most appropriate solution would look like.
Just to give an example of using dictionaries (as they have been mentioned here in other answers) in case you find it useful.
def get_list1():
print('get_list1 executes')
def get_list2():
print('get_list2 executes')
# Create a dictionary with a reference to your functions as values
# (note no parenthesis, as that would execute the function here instead)
fns = {
'example_key1': get_list1,
'example_key2': get_list2,
}
print(type(fns['example_key1'])) # returns <class 'function'>
# If you still want a list
lst = list(fns) # Create a list containing the keys of the fns dictionary
for fn in lst:
# Iterate through the list (of keys) and execute the function
# found in the value.
fns[fn]()
# Or you can now just simply iterate through the dictionary instead, if you wish:
for fn in fns.values():
fn()
This code produces:
<class 'function'>
get_list1 executes
get_list2 executes
get_list1 executes
get_list2 executes
fn = vars()['get_' + list_item]
fn()

When a particular key is not present in a dictionary

From a Dictionary input_dict={'Name': 'Monty', 'Profession': 'Singer' }, get the value of a key Label which is not a part of the dictionary, in such a way that Python doesn't hit an error. If the key does not exist in the dictionary, Python should return NA.
Sample Input:
{'Name': 'Monty', 'Profession': 'Singer' }
Sample Output:
NA
The get() method is really useful here as it returns none and don't break the system by giving error
You can use get method of the dictionary. This method never raises a KeyError.
input_dict.get('Label', 'NA')
The syntax of get() is:
dict.get(key, value)
get() Parameters
The get() method takes maximum of two parameters:
key - key to be searched in the dictionary
value (optional) - Value to be returned if the key is not found. The
default value is None.
The get() method returns:
the value for the specified key if key is in dictionary.
None if the key is not found and value is not specified.
value if the key is not found and value is specified.
import ast,sys
input_str = sys.stdin.read()
input_dict = ast.literal_eval(input_str)
answer=input_dict.get('Label', 'NA')
print(answer)
Final solution can be with use of Get().
import ast, sys
input_str = sys.stdin.read()
input_dict = ast.literal_eval(input_str)
answer = input_dict.get('Label', 'NA')
print(answer)
It is working fine
We use update statement to update the Label and so when call the label, we the value of "NA"
import ast,sys
input_str = sys.stdin.read()
input_dict = ast.literal_eval(input_str)
input_dict.update({'Label':'NA'})
answer=input_dict["Label"]
print(answer)
import ast,sys
input_str = sys.stdin.read()
input_dict = ast.literal_eval(input_str)
input_dict["Label"]="NA"
answer=input_dict["Label"]
# Type your answer here
print(answer)

Python get #property.setter decorated method in a class

In Python there is no switch/case. It is suggested to use dictionaries: What is the Python equivalent for a case/switch statement?
in Python it is good practise to use #property to implement getter/setter: What's the pythonic way to use getters and setters?
So, if I want to build a class with a list of properties to switch so I can get or update values, I can use something like:
class Obj():
"""property demo"""
#property
def uno(self):
return self._uno
#uno.setter
def uno(self, val):
self._uno = val*10
#property
def options(self):
return dict(vars(self))
But calling
o=Obj()
o.uno=10 # o.uno is now 100
o.options
I obtain {'_uno': 100} and not {'uno': 100}.
Am I missing something?
vars is really a tool for introspection, and gives you the local variables of the current space, or in a given object - it is not a good way to get attributes and variables ready for final consumption.
So, your options code must be a bit more sophisticated - one way to go
is to search the class for any properties, and then using getattr to get
the values of those properties, but using the getter code, and
introspect the instance variables, to get any methods attributed directly,
but discard the ones starting with _:
#property
def options(self):
results = {}
# search in all class attributes for properties, including superclasses:
for name in dir(self.__class__):
# obtain the object taht is associated with this name in the class
attr = getattr(self.__class__, name)
if isinstance(attr, property):
# ^ if you want to also retrieve other "property like"
# attributes, it is better to check if it as the `__get__` method and is not callable:
# "if hasattr(attr, '__get__') and not callable(attr):"
# retrieves the attribute - ensuring the getter code is run:
value = getattr(self, name)
results[name] = value
# check for the attributes assigned directly to the instance:
for name, value in self.__dict__.items():
# ^ here, vars(self) could have been used instead of self.__dict__
if not name.startswith("_"):
results[name] = value
return results
about switch..case
On a side note to your question, regarding the "switch...case" construction: please disregard all content you read saying "in Python one should use dictionaries instead of switch/case". This is incorrect.
The correct construct to replace "switch...case" in Python is the "if..elif..else". You can have all the expressiveness one does have with a C-like "switch" with a plain "if-else" tree in Python, and actually, go much beyond that, as the testing expression in if...elif can be arbitrary, and not just a matching value.
option = get_some_user_option()
if option == "A":
...
elif option == "B":
...
elif option in ("C", "D", "E"):
# common code for C, D, E
...
if option == "E":
# specialized code for "E",
else:
# option does not exist.
...
While it is possible to use a dictionary as a call table, and having functions to perform actions in the dictionary values, this construct is obviously not a "drop in" replacement for a plain switch case - starting from the point that the "case" functions can't be written inline in the dictionary, unless they can be written as a lambda function, and mainly
the point that they won't have direct access to the variables on the function calling them.

Dictionary to switch between methods with different arguments

A common workaround for the lack of a case/switch statement in python is the use of a dictionary. I am trying to use this to switch between methods as shown below, but the methods have different argument sets and it's unclear how I can accommodate that.
def method_A():
pass
def method_B():
pass
def method_C():
pass
def method_D():
pass
def my_function(arg = 1):
switch = {
1: method_A,
2: method_B,
3: method_C,
4: method_D
}
option = switch.get(arg)
return option()
my_function(input) #input would be read from file or command line
If I understand correctly, the dictionary keys become associated with the different methods, so calling my_function subsequently calls the method which corresponds to the key I gave as input. But that leaves no opportunity to pass any arguments to those subsequent methods. I can use default values, but that really isn't the point. The alternative is nested if-else statements to choose, which doesn't have this problem but arguably less readable and less elegant.
Thanks in advance for your help.
The trick is to pass *args, **kwargs into my_function and the **kwargs onto to your choosen function and evaluate it there.
def method_A(w):
print(w.get("what")) # uses the value of key "what"
def method_B(w):
print(w.get("whatnot","Not provided")) # uses another keys value
def my_function(args,kwargs):
arg = kwargs.get("arg",1) # get the arg value or default to 1
switch = {
1: method_A,
2: method_B,
}
option = switch.get(arg)
return option(kwargs)
my_function(None, {"arg":1, "what":"hello"} ) # could provide 1 or 2 as 1st param
my_function(None, {"arg":2, "what":"hello"} )
Output:
hello
Not provided
See Use of *args and **kwargs for more on it.

AWS Lambda Python 3 check event variable exists

try:
event['ids']
except NameError:
ids = None
This is throwing a KeyError. I just want to check if the event variable exists and set to none or pass the value if it does.
I have also tried to use
if (len(event['ids']) < 1)
but get an error.
Am I missing something? I may or may not have all my event keys passed and want to check for existence.
Use the get method. The second parameter is the default value if the key doesn't exist in the dictionary. It's the standard way to get values from a dictionary when you're not sure if the key exists and you don't want an exception.
ids = event.get('ids', None)
We can check if the key 'key1' exists in the Json dictionary.
{
"key1":"value1"
}
To retrieve the value 'value1' if the key 'key1' exists in the dictionary.
if event.get('key1',None) != None:
value = event.get('key1',None)

Resources