KeyError: 'pop from an empty set' python - python

How do you get around this error while using .pop? I get that when it tries to return a number but there isn't one an error is raised but how do you get around it so the program keeps running?
def remove_element(self,integer):
self.integer = integer
self.members.pop()

Just check if self.members is not empty:
if self.members:
self.members.pop()
or, catch KeyError via try/except:
try:
self.members.pop()
except KeyError:
# do smth

You can use try/except to catch the KeyError raised by an_empty_set.pop(), or check the set first to make sure it's not empty:
if s:
value = s.pop()
else:
# whatever you want to do if the set is empty

Single line solution
res = self.members.pop() if self.members else None

Related

How to differentiate between cases of ValueError

Since too many python operations return ValueError, how can we differentiate between them?
Example: I expect an iterable to have a single element, and I want to get it
a, = [1, 2]: ValueError: too many values to unpack
a, = []: ValueError: too few values to unpack
How can I differentiate between those two cases?? eg
try:
a, = lst
except ValueError as e:
if e.too_many_values:
do_this()
else:
do_that()
I realise that in this particular case I could find a work-around using length/indexing, but the point is similar cases come up often, and I want to know if there's a general approach. I also realise I could check the error message for if 'too few' in message but it seems a bit crude.
try:
raise ValueError('my error')
except ValueError as e:
# use str(), not repr(), see
# https://stackoverflow.com/a/45532289/7919597
x = getattr(e, 'message', str(e))
if 'my error' in x:
print('got my error')
(see also How to get exception message in Python properly)
But this might not be a clean solution after all.
The best thing would be to narrow the scope of your try block so that only one was possible. Or don't depend on exceptions to detect those error cases.
This isn't really an answer, because it only applies if you have some control over how the exceptions are raised. Since exceptions are just objects, you can just tack on other objects / flags to them. Not saying that this is a great thing to do or a great way of doing it:
from enum import Enum
class ValueErrorType(Enum):
HelloType = 0,
FooType = 1
def some_func(string):
if "Hello" in string:
error = ValueError("\"Hello\" is not allowed in my strings!!!!")
error.error_type = ValueErrorType.HelloType
raise error
elif "Foo" in string:
error = ValueError("\"Foo\" is also not allowed!!!!!!")
error.error_type = ValueErrorType.FooType
raise error
try:
some_func("Hello World!")
except ValueError as error:
error_type_map = {
ValueErrorType.HelloType: lambda: print("It was a HelloType"),
ValueErrorType.FooType: lambda: print("It was a FooType")
}
error_type_map[error.error_type]()
I'd be curious to know if there is some way you can achieve this with exceptions where you have no control over how they're raised.

Is there a python set deleting method that returns a value if the value you want to delete is not in the set?

Is there a deleting method for deleting an element of a set that takes a parameter to return if there is no element to delete that matches the parameter you gave it to delete?
So it would be something like set.discard(a,b) where a is the parameter that you want to delete and b is the parameter that gets returned if a is not found.
Something like this?
def _discard(s, key, ret):
try:
s.remove(key)
except KeyError:
return ret
return key
s = set([1,2,3])
ret = "not found"
key = 4
print _discard(s, key, ret), s
key = 3
print _discard(s, key, ret), s
Not built-in.
remove(elem)
remove(elem)
Remove element elem from the set. Raises KeyError if elem is not contained in the set.
Try to catch the exception in your own function maybe?
When exception caught return your element b.

Multiple Try Except when the value may not be present

I need to check one or another environment variable.
With casual variables - I can use:
if var1:
print('Var1 found')
elif var2:
print('Var2 found')
else:
print('Neither Var1 nor Var2 not found')
How can I do same for environment variables?
I can't use if/else, because of if variable not found - os.environ will raize KeyError:
File "C:\Python27\lib\os.py", line 425, in __getitem__
return self.data[key.upper()]
KeyError: 'BAMBOO_WORKING_DIRECTORY'
If I'll do two try/except, like:
try:
r = os.environ['Var1']
except KeyError as error:
print('Var1 not found')
try:
r = os.environ['Var2']
except KeyError as error:
print('Var2 not found')
So, it will check both of them. But I need Var1 or Var2.
Add if/else after first try/except, to check if r: an call second try/except if not? Will looks disgusting...
os.environ is a dict, so you can use the .get call on it with default value.
If you use the two .get calls in conjunction, then this will get you the first variable, if it is present (because of python short circuiting), else it will get you the second one.
So essentially, the code is simplified to:
r = os.environ.get('Var1', "") or os.environ.get('Var2', "")
In this case, there is no need of a try - except block.
Chain this slightly longer, and you can get the expression which will give the default value as well:
>>> r = os.environ.get('Var1', "") or os.environ.get('Var2', "") or (
"Neither Var1 nor Var2 not found")
The exact equivalent of your if/elif for known variables (but for environment variables) would be:
from os import environ
if environ.get("VAR1"):
print('VAR1 found')
elif environ.get("VAR2"):
print('VAR2 found')
else:
print('Neither VAR1 nor VAR2 not found')
Since os.environ is a dict and dict.get has a signature of dict.get(key, [default]) where default defaults to None you can take advantage of this and get None back for key(s) that don't exist (which evaluate Falsely).
How about using a for loop?
for varname in ['Var1', 'Var2']:
try:
r = os.environ['Var1']
break
except KeyError as error:
print('{} not found'.format(varname))
You can nest your try statements
try:
r = os.environ['Var1']
try:
r = os.environ['Var2']
except KeyError as error:
print('Var2 not found')
except KeyError as error:
print('Var1 not found')

Raising an exception

This is a homework problem. I've been trying to solve it but couldn't get the right result.
This is the question:
Write a function string2int that attempts to convert a string to an integer. If the string does represent a positive integer then that integer should be returned. If the string does not represent a positive integer then you should raise a syntax exception (raise SyntaxError('not an integer')).
You may choose to use the (already defined) function all_digits that takes a string and returns True if all the characters of the string are digits and False otherwise.
What I've got so far is:
try all_digits is True:
return int(num)
except all_digits is False:
raise SyntaxError('not an integer')
Because I'm using an already defined function, I didn't define a function (or did I get it wrong?).
Can anyone have a look at my code please? Much appreciated.
I can guess, but you might want to tell us what kind of error you get when you execute the code (just a heads up for the next time you ask a question).
There's a couple of mistakes:
1) The syntax of
try all_digits is True:
is wrong. The "try" statement should look like this:
try:
<your code>
except <type of exception to catch>:
<error handling code>
2) You said "all_digits" is a function. Therefore, the code
all_digits is True
should be
if all_digits(num):
Putting it all together:
def string2int(num):
if all_digits(num):
return int(num)
raise SyntaxError('not an integer')
In addition to Rawing's excellent answer, note that the usual time to use try/except is when you can handle the error thrown in the try block and continue as usual. For instance:
def add_three(x) -> int:
try:
return x + 3
except TypeError:
# someone passed a non-int/float to the function!
# let's try and coerce it.
return int(x) + 3
# if this still throws an exception, we'll let it
# raise its own TypeError exception!
In your case it looks like you're just doing regular conditionals, so use if all_digits(num): return int(num) else: raise TypeError('not an integer')
all_digits(string) function:
First, it's good to understand what does the pre-defined all_digits(string) function do. Following is a sample implementation of that function, which works as desired by your description. It checks whether each letter of the string is a digit and returns a boolean, True or False, accordingly:
def all_digits(string):
''' only returns True if all characters of the string are Integers '''
for l in string:
if l.isdigit(): pass
else: return False
return True
string2num(string) function with raise statement:
Now, we can use this function in our error handling block of the string2num(string) function. Since your problem requires you to only raise a specific exception and not to continue with an alternate block of code, you do not need the try: ... except: block.
With the proper syntax of the raise statement, we can write:
def string2num( string = '-23'):
if all_digits(string):
return int('23')
raise SyntaxError("not an integer")
and we get:
>>> string2num()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 4, in string2num
SyntaxError: not an integer
with try: ... except: ... block:
But if you do want to execute an alternate block of code when the exception is raised, you can use the try: ... except: block syntax. You may need it, for instance, if you want to further check if the string is a negative integer and if so then return the negative integer:
def string2num( string = '-23'):
try:
if all_digits(string):
return int(string)
raise SyntaxError("not an integer")
except SyntaxError:
#alternate code goes here#
try:
return int(string)
except ValueError:
print "string contains an alphabet"
This will produce:
>>> string2num()
-23
>>> string2num('ab2')
string contains an alphabet
Style for if statement:
As a side note on your style, you don't have to explicitly write whether an expression evaluates to True or False in an if statement, like so:
if all_digits(string) is True:
Since all_digits(string) returns a boolean, you can equivalently just say if True, like so:
if all_digits(string):

Python's way to store a default value if expression failed

What is the python analog of perl's // operator?
In perl, one can do something like :
$pos = $some_list[0] // 1
How do you accomplish the same in python?
In Python there is no undefined; instead, you'd get an exception if you tried to access an non-existent index in a list. As such, you can use exception handling instead:
try:
pos = some_list[0]
except IndexError:
pos = 1
For the first element of a sequence, you could explicitly test the sequence as a boolean (a python container is 'falsey' when empty):
post = some_list[0] if some_list else 1
How about using exceptions?
try:
pos = some_list[0]
except (NameError, IndexError):
pos = 1
An alternative to try/catch answers above for dictionaries is the default argument on .get():
param_value = my_dictionary.get(param_key, default_value)
The best practice for this in python is to handle exceptions explicitly with a try, except clause. One example presented here to help you visuallize
my_list = []
try:
item = my_list[1]
except IndexError:
item = 1
Here the code executes and an exception is raised because the index "1" is out of bounds. We then go on to handle that exception and set item=1 allowing the program to continue running. The reason for this explicit handling of exceptions is so we as programmers see exactly what is causing our problems. Take this for example:
my_list = [0]
try:
item = 1/my_list[0]
except IndexError:
item = 1
This will raise a zero division error (halting execution) and let us know that we need to handle some other exception explicitly beyond the original exception we expected, the IndexError. We might then do something like this to deal with that situation:
my_list = [0]
try:
item = 1/my_list[0]
except IndexError:
item = 1
except ZeroDivisionError:
item = 99999
try-except blocks also have a few other notable features we can exploit:
try:
# code which might raise error
pass
except IndexError as err:
# handling an index error and storing the traceback in err
pass
except ZeroDivisionError:
#handling some other error:
pass
else:
# code we would like to execute if the try block succeeds without any errors
pass
finally:
# code we will execute regardless of what occurs in the entire
# try,except,else block listed above (i.e we can ensure a file is closed)
pass

Categories

Resources