How to combine try/except in python into a pretty one liner? - python

In order to make CSV files with many columns, I have many, many instances of
try:
printlist.append(text['data'])
except:
printlist.append('')
Is it possible to condense these 4 lines into 1 or 2 (mostly for easier reading of the code)? I've tried with this function but I haven't discovered a way to pass something that doesn't exist.
def tryexcept(input):
try:
printlist.append(input)
except:
printlist.append('')
return printlist
UPDATE I should mention that 'text' is actually a dict value, so it should look like
printlist.append(text['data'])
(changed above)

What about:
printlist.append(text['data'] if 'data' in text else '')
Or even better as #bruno desthuilliers suggested:
printlist.append(text.get('data',''))
[EDIT]
For nested dict I normally use my dict selector:
class TokenDataType:
LIST = "list"
DICT = "dict"
def _select_key(keyitt, data):
try:
new_key = keyitt.next()
except StopIteration:
return data
if new_key["t"] == TokenDataType.DICT:
return _select_key(keyitt, data[new_key["k"]])
elif new_key["t"] == TokenDataType.LIST:
return _select_key(keyitt, data[new_key["i"]])
def tokenize_query(query):
tokens = []
for token in query.split("."):
token = token.strip()
if token:
ttype = TokenDataType.LIST if "[" in token else TokenDataType.DICT
if ttype == TokenDataType.LIST:
index = None
if len(token) >= 3:
index = int(token.replace("[", "").replace("]", ""))
tokens.append({"k":token, "t":ttype, "i":index})
else:
tokens.append({"k":token, "t":ttype})
return tokens
def normalize_query(query=None, tokens=None):
if tokens == None:
tokens = tokenize_query(query)
return ".".join([token["k"] for token in tokens])
def select(query, data, throw_exception_on_key_not_found=False):
tokens = tokenize_query(query)
try:
return _select_key(iter(tokens), data)
except Exception as e:
if throw_exception_on_key_not_found:
raise e
return None
DQ = select
if __name__ == "__main__":
test = {"bla":1, "foo":{"bar":2}, "baz":[{"x":1}, {"x":2}]}
print(DQ(".bla", test))
print(DQ("bla", test))
print(DQ("nothere", test))
print(DQ(".foo", test))
print(DQ("foo.bar", test))
print(DQ("baz", test))
print(DQ("baz.[0]", test))
print(DQ("baz.[1].x", test))
print(DQ("baz.[2].x", test))
for your case (appends None when one of the keys is not found):
printlist.append(DQ("data.someotherkey.yetanotherkey", text))

There's a dictionary method that does exactly this, and it let's you specify any default value.
input = text.get('data', default='')
printlist.append(input)
It checks if the key exists in the dictionary, and if not, it returns the default value. More on dictionaries here.

Try this simple wrapper:
def execute_with_exception_handling(f):
try:
return f()
except:
raise
Then you execute your function:
def my_func():
return 0 / 0
execute_with_exception_handling(my_func)
You can also add arguments to the function with *args. And you can even use decorators...that you can google because I recall off the top of my head how that works.

Why do you need to pass something that does not exist?
You can simply call function if the value that is being passed in is not "None" (Or any other unwanted value).
tryexcept( x ) if x is not None else None
Edit:
Are you are trying to see if the variable is declared or not? If yes, one way to get around this would be to declare the variable beforehand:
x = None
...
tryexcept( x ) if x is not None else None

Related

Handle nested fields with conversion types in string with string.Formatter

Update 2
Alright, my answer to this question is not a complete solution to what I originally wanted but it's ok for simpler things like filename templating (what I originally intended to use this for). I have yet to come up with a solution for recursive templating. It might not matter to me though as I have reevaluated what I really need. Though it's possible I'll need bigger guns in the future, but then I'll probably just choose another more advanced templating engine instead of reinventing the tire.
Update
Ok I realize now string.Template probably is the better way to do this. I'll answer my own question when I have a working example.
I want to accomplish formatting strings by grouping keys and arbitrary text together in a nesting manner, like so
# conversions (!):
# u = upper case
# l = lower case
# c = capital case
# t = title case
fmt = RecursiveNamespaceFormatter(globals())
greeting = 'hello'
person = 'foreName surName'
world = 'WORLD'
sample = 'WELL {greeting!u} {super {person!t}, {tHiS iS tHe {world!t}!l}!c}!'
print(fmt.format(sample))
# output: WELL HELLO Super Forename Surname, this is the World!
I've subclassed string.Formatter to populate the nested fields which I retrieve with regex, and it works fine, except for the fields with a conversion type which doesn't get converted.
import re
from string import Formatter
class RecursiveNamespaceFormatter(Formatter):
def __init__(self, namespace={}):
Formatter.__init__(self)
self.namespace = namespace
def vformat(self, format_string, *args, **kwargs):
def func(i):
i = i.group().strip('{}')
return self.get_value(i,(),{})
format_string = re.sub('\{(?:[^}{]*)\}', func, format_string)
try:
return super().vformat(format_string, args, kwargs)
except ValueError:
return self.vformat(format_string)
def get_value(self, key, args, kwds):
if isinstance(key, str):
try:
# Check explicitly passed arguments first
return kwds[key]
except KeyError:
return self.namespace.get(key, key) # return key if not found (e.g. key == "this is the World")
else:
super().get_value(key, args, kwds)
def convert_field(self, value, conversion):
if conversion == "u":
return str(value).upper()
elif conversion == "l":
return str(value).lower()
elif conversion == "c":
return str(value).capitalize()
elif conversion == "t":
return str(value).title()
# Do the default conversion or raise error if no matching conversion found
return super().convert_field(value, conversion)
# output: WELL hello!u super foreName surName!t, tHiS iS tHe WORLD!t!l!c!
What am I missing? Is there a better way to do this?
Recursion is a complicated thing with this, especially with the limitations of python's re module. Before I tackled on with string.Template, I experimented with looping through the string and stacking all relevant indexes, to order each nested field in hierarchy. Maybe a combination of the two could work, I'm not sure.
Here's however a working, non-recursive example:
from string import Template, _sentinel_dict
class MyTemplate(Template):
delimiter = '$'
pattern = '\$(?:(?P<escaped>\$)|\{(?P<braced>[\w]+)(?:\.(?P<braced_func>\w+)\(\))*\}|(?P<named>(?:[\w]+))(?:\.(?P<named_func>\w+)\(\))*|(?P<invalid>))'
def substitute(self, mapping=_sentinel_dict, **kws):
if mapping is _sentinel_dict:
mapping = kws
elif kws:
mapping = _ChainMap(kws, mapping)
def convert(mo):
named = mapping.get(mo.group('named'), mapping.get(mo.group('braced')))
func = mo.group('named_func') or mo.group('braced_func') # i.e. $var.func() or ${var.func()}
if named is not None:
if func is not None:
# if named doesn't contain func, convert it to str and try again.
callable_named = getattr(named, func, getattr(str(named), func, None))
if callable_named:
return str(callable_named())
return str(named)
if mo.group('escaped') is not None:
return self.delimiter
if mo.group('invalid') is not None:
self._invalid(mo)
if named is not None:
raise ValueError('Unrecognized named group in pattern',
self.pattern)
return self.pattern.sub(convert, self.template)
sample1 = 'WELL $greeting.upper() super$person.title(), tHiS iS tHe $world.title().lower().capitalize()!'
S = MyTemplate(sample1)
print(S.substitute(**{'greeting': 'hello', 'person': 'foreName surName', 'world': 'world'}))
# output: WELL HELLO super Forename Surname, tHiS iS tHe World!
sample2 = 'testing${äää.capitalize()}.upper()ing $NOT_DECLARED.upper() $greeting '
sample2 += '$NOT_DECLARED_EITHER ASDF$world.upper().lower()ASDF'
S = MyTemplate(sample2)
print(S.substitute(**{
'some_var': 'some_value',
'äää': 'TEST',
'greeting': 'talofa',
'person': 'foreName surName',
'world': 'världen'
}))
# output: testingTest.upper()ing talofa ASDFvärldenASDF
sample3 = 'a=$a.upper() b=$b.bit_length() c=$c.bit_length() d=$d.upper()'
S = MyTemplate(sample3)
print(S.substitute(**{'a':1, 'b':'two', 'c': 3, 'd': 'four'}))
# output: a=1 b=two c=2 d=FOUR
As you can see, $var and ${var} works as expected, but the fields can also handle type methods. If the method is not found, it converts the value to str and checks again.
The methods can't take any arguments though. It also only catches the last method so chaining doesn't work either, which I believe is because re do not allow multiple groups to use the same name (the regex module does however).
With some tweaking of the regex pattern and some extra logic in convert both these things should be easily fixed.
MyTemplate.substitute works like MyTemplate.safe_substitute by not throwing exceptions on missing keys or fields.

Any trick to override idex() function in Python so exception won't be raised if a string is not found

a = 'abc'
print(a.index('q'))
it obviously returns -1 but also an exception, so my question is simply how to remove the exception from the output and let -1 as the output only.
I would rather say handle the exception instead of trying to override the built-in function like:
try:
ind = string.index(substring)
print (ind)
except:
return f"{substring} does not exist in {string}"
But if you still want to override it here is one of the approach:
def index(string, substring):
try:
ind = string.index(substring)
return ind
except:
return f"{substring} does not exist in {string}"
a = "abc"
print(index(a, 'c'))

Why is my attempt to unpack a map resulting in `TypeError: 'int' object is not iterable`

I know that TypeError: 'int' object is not iterable occurs when we try to iterate over something which is not iterable. For example,
for x in 4:
pass
m = map(str, 99)
In my case, I construct a map, and even though there is a problem, it doesn't fail until later. Something like the following line executes just fine
m = map(foo, [1, 2, 3])
The issue is with my function foo. Later, when I try to unpack the map-iterator, such as by writing list(m), foo raises the TypeError I just can't figure out why.
import itertools
def contains_iter(cont):
"""
returns true if container is an iterator
or
if container is not an iterator
but container contains an iterator
or
if container is not an iterator
but container contains a container
which contains an iterator.
etc...
"""
range_type = type(range(1))
if hasattr(cont, "__next__") or isinstance(cont, range_type):
return True
try:
for elem in cont:
if elem == cont:
# string "a" in "a"
break
if contains_iter(elem):
return True
r = False
except TypeError:
# object is not iterable
r = False
finally:
pass
return r
def deiter(it):
status = contains_iter(it)
if status:
assert(hasattr(it, "__iter__"))
mahp = map(deiter, it)
tup = tuple(mahp)
return tup
return it
def print_io(inny):
def outty(*args):
args = deiter(args)
try:
output = inny(*args)
except BaseException as exc:
output = str(type(exc)) + str(exc)
output = deiter(output)
call_sig = "flatten" + str(args)
output = "OUTPUT: " + str(output)
print(40*"#", call_sig, output, 40*"#", sep="\n")
return
return outty
class FlatClass:
def __call__(self, *args):
try:
if len(args) <= 1:
try:
r = iter(args[0])
except BaseException:
r = args[0]
# if len(args) == 0
# `args[0]` raises
# exception
else:
args = map(self, args)
r = itertools.chain(*args)
except IndexError:
r = tuple() # empty tuple
finally:
pass
return r
flatten = print_io(FlatClass())
flatten(1, [2])
You've got an itertools.chain call that's trying to chain things that aren't iterables:
else:
args = map(self, args)
r = itertools.chain(*args)
Some of those arguments are integers. This isn't detected when the chain iterator is created, only when you eventually try to iterate over it.
With no idea what the goal of this code was, we can't say how to fix it. There are plenty of other parts of this code that are suspicious (ranges aren't iterators), purposeless (finally: pass), or needlessly convoluted (range_type = type(range(1)) just sets range_type = range), and there are almost certainly more bugs, but this is the one causing the immediate problem.

Best way to check key value with dictionary in python

I have a dictionary and I want to add some index of the dictionary to variables.
I know that try except is more pythonic than else if. And I tried with try except and it's works perfectly but I have a lot of key to check and I can't figure out of which code is more pythonic
Here is my dictionary :
test = {"token":"eating", "stemm": "eat", "lemm": "eat", "pos":"VPP"}
def method_one(test):
try:
token = test["token"]
except KeyError:
token = None
try:
stemm = test["stemm"]
except KeyError:
stemm = None
def method_two(test):
token = None
stemm = None
if "token" in test:
token = test["token"]
if "stemm" in test:
stemm = test["stemm"]
I also tried one try except for all but when one failed, I can't know which one is failing so this is useless.
Any ideas of a third method? Or method one is the good one?
dict has get method that will return value or None. you could do item = dict.get(key) and this will return either the value(if the key exists) or None otherwise, which is what you are looking for it seems :)
>>> d = {'foo': 'bar'}
>>> d.get('foo')
'bar'
>>> item = d.get('fooo')
>>> item is None
True
There is a direct lookup construct where create a set of valid keys that should exist in the dictionary
test = {"token":"eating", "stemm": "eat", "lemm": "eat", "pos":"VPP"}
def validate(d, valkeys):
keyset = set(test.keys())
if valkeys.issubset(keyset):
return True
else:
return False
if __name__ == "__main__":
val = set(["token", "stemm"])
inval = set(["token", "stemm", "st"])
assert validate(test, val) == True
assert validate(test, inval) == False

The Pythonic way of validating a long chain of conditions in Python

So I have a long chain of conditions that should be validated to be true. Instead of chaining a long if condition, I tried to be "innovative" and did it this way, which I reckon is more readable. But my question is, is this the optimal way of doing it?
Or is there a pythonic way of doing it? PS: Please respond with an alternative instead of answering "No", thanks!
Here's the code chunk:
def site_exists(site):
"""
returns the sitebean if it exists,
else returns false
"""
vpadmin_service = _get_vpadmin_service(site)
all_sites = VpAdminServiceUtil.getSites(vpadmin_service)
for site_listing in all_sites:
if site.getId():
#condition check
try:
assert site.getId() == site_listing.getId()
assert site.getName() == site_listing.getName()
assert site.getCustomer().getId() == site_listing.getCustomer().getId()
except AssertionError:
continue
#pass conditions
return site_listing
#no id, so just check for name and customer
else:
#condition check
try:
assert site.getName() == site_listing.getName()
assert site.getCustomer().getId() == site_listing.getCustomer().getId()
except AssertionError:
continue
#pass conditions
site.setId(site_listing.getId())
return site_listing
return False
A simpler approach is to build a tuple of the conditions and compare the tuples:
def site_info(s):
return s.getId(), s.getName(), s.getCustomer().getId()
if site_info(site) == site_info(site_listing):
return site_listing
else:
continue
If you have a lot of conditions, or the conditions are expensive, you can instead create a generator for the conditions, and compare with any or all:
import itertools
def iter_site_info(s):
yield s.getId()
yield s.getName()
yield s.getCustomer().getId()
if all(x==y for (x, y) in itertools.izip(iter_site_info(site), iter_site_info(site_listing)):
return site_listing
else:
continue
I'm not sure whether Jython has any and all, but they're trivial functions to write.
EDIT - any and all appeared in Python 2.5, so Jython should have them.
Using exception for control flow is bad! And it will also kill your performance. Assuming the condition will be true in one out of 10 cases? So 9 exceptions to handle in the worst case - this comes with a huge performance cost.
If you want readability, try:
if (
condition1 and \
condition2 and \
condition3
):
# do something
For the revised version, this should be equivalent:
for site_listing in all_sites:
if site.getName() == site_listing.getName() and site.getCustomer().getId() == site_listing.getCustomer().getId():
if not site.getId():
site.setId(site_listing.getId())
if site.getId() == site_listing.getId():
return site_listing
I would implement an is_same method on site and call it in the for loops.
all_sites = VpAdminServiceUtil.getSites(vpadmin_service)
for site_listing in all_sites:
if site_listing.is_same(site, set_id=True):
return site_listing
As for its implementation (that is your real question), I suggest something like:
...
if self.getName() != site.getName(): return False
if self.getCustomer() != site.getCustomer(): return False
...
return True
Use the __eq__ method! If you wrote the class of site yourself, no problem. If it is from a module outside of your control, see this solution, or create a somewhat less elegant wrapping class. For the wrap variant, this would be the class:
class WrappedSite(object):
def __init__(self, site):
self.site = site
def __eq__(self, other):
if site.getId():
if self.site.getId() != other.site.getId():
return False
if self.site.getName() != other.site.getName():
return False
if self.site.getCustomer().getId() != other.site.getCustomer().getId():
return False
return True
Then your big ugly function is reduced to this:
def site_exists(site):
"""
returns the sitebean if it exists,
else returns false
"""
vpadmin_service = _get_vpadmin_service(site)
all_sites = VpAdminServiceUtil.getSites(vpadmin_service)
wsite = WrappedSite(site)
for site_listing in all_sites:
if wsite == WrappedSite(site_listing):
return site_listing
return False
EDIT Fixed site_exists to return sitebean instead of True.
Remove some code duplication:
def site_exists(site):
"""
returns the sitebean if it exists,
else returns None
"""
vpadmin_service = _get_vpadmin_service(site)
all_sites = VpAdminServiceUtil.getSites(vpadmin_service)
for site_listing in all_sites:
if (site.getName() == site_listing.getName() and
site.getCustomer().getId() == site_listing.getCustomer().getId()):
if site.getId(): # if id is set; it should be the same
if site.getId() != site_listing.getId(): continue
else: # no id; consider it the same site
site.setId(site_listing.getId()) #XXX side-effect
return site_listing
Note: it is unexpected that site_exists() might modify its argument (via .setId()). Consider to refactor it:
def same_site(site, other):
if site.getId() and site.getId() != other.getId():
# if id is set; it should be the same
return False
return (site.getName() == other.getName() and
site.getCustomer().getId() == other.getCustomer().getId())
def get_site_listing(site):
"""
returns the sitebean corresponding to `site`,
returns None if there is none
"""
vpadmin_service = _get_vpadmin_service(site)
all_sites = VpAdminServiceUtil.getSites(vpadmin_service)
return next((s for s in all_sites if same_site(site, s)), None)
Note: the code doesn't modify the site object. Use the return value from get_site_listing() instead.
If next() is unavailable then use:
for site_listing in all_sites:
if same_site(site, site_listing):
return site_listing
return None
btw, jython should provide property wrappers for you; so you could write:
def same_site(site, other):
if site.id and site.id != other.id:
# if id is set; it should be the same
return False
return site.name == other.name and site.customer.id == other.customer.id
and site.id = id instead of site.setId(id).
Using an exception handler as a code target is basically a "goto". I don't see anything wrong with it really (despite the ancient furor surrounding "goto considered harmful"), but knowing that it's a goto might give you a different perspective.
Using exception handling for control flow is pythonic in the sense that "it's easier to ask for forgiveness than for permission". However, that doesn't extend to making rules to break just so that you can ask for forgiveness.
Others have provided excellent alternatives. Just wanted to address the principle aspect.

Categories

Resources