Do I have to cause an ValueError in Python - python

I have this code:
chars = #some list
try:
indx = chars.index(chars)
except ValueError:
#doSomething
else:
#doSomethingElse
I want to be able to do this because I don't like knowfully causing Exceptions:
chars = #some list
indx = chars.index(chars)
if indx == -1:
#doSomething
else:
#doSomethingElse
Is there a way I can do this?

Note that the latter approach is going against the generally accepted "pythonic" philosophy of EAFP, or "It is Easier to Ask for Forgiveness than Permission.", while the former follows it.

if element in mylist:
index = mylist.index(element)
# ... do something
else:
# ... do something else

For the specific case where your list is a sequence of single-character strings you can get what you want by changing the list to be searched to a string in advance (eg. ''.join(chars)).
You can then use the .find() method, which does work as you want. However, there's no corresponding method for lists or tuples.
Another possible option is to use a dictionary instead. eg.
d = dict((x, loc) for (loc,x) in enumerate(chars))
...
index = d.get(chars_to_find, -1) # Second argument is default if not found.
This may also perform better if you're doing a lot of searches on the list. If it's just a single search on a throwaway list though, its not worth doing.

Related

Dynamically look for index() in list from set of options

def _parse_options(productcode_array):
if not self._check_productcode_has_options(productcode_array):
return None
possible_options = {"UV1", "UV2", "Satin", "Linen", "Unco", "Natural"}
option_index = productcode_array.index()
Example value of productcode_array:
["BC", "1.5x3.5", "100lb", "Linen", "Q100"]
My initial thought was to maybe try/except with a list comprehension but I feel there's probably a cleaner way I don't know about.
What I'm trying to achieve is getting the index position within my list productcode_array where any 1 of the possible_options exist. I know there will always only be 1 of the options present. The reason I need this is because the index position within the productcode is dependent on a number of factors.
What would be a clean and effective way to use index() with each of the values of my possible_options set?
>>> next(i for i, code in enumerate(productcode_array) if code in possible_options)
3
or
>>> productcode_array.index(possible_options.intersection(productcode_array).pop())
3
Example with try/except:
for x in possible_options:
try:
option_index = productcode_array.index(x)
except ValueError:
pass
This does work, but it feels dirty, so open to cleaner options.
You could use set.intersection and then assign to option_index (assuming there's only one common value, as stated in the comments):
For example:
possible_options = {"UV1", "UV2", "Satin", "Linen", "Unco", "Natural"}
productcode_array = ["BC", "1.5x3.5", "100lb", "Linen", "Q100"]
for v in possible_options.intersection(productcode_array):
option_index = productcode_array.index(v)
print(option_index)
Prints:
3

Python elegant way to map string structure

Let's say I know beforehand that the string
"key1:key2[]:key3[]:key4" should map to "newKey1[]:newKey2[]:newKey3"
then given "key1:key2[2]:key3[3]:key4",
my method should return "newKey1[2]:newKey2[3]:newKey3"
(the order of numbers within the square brackets should stay, like in the above example)
My solution looks like this:
predefined_mapping = {"key1:key2[]:key3[]:key4": "newKey1[]:newKey2[]:newKey3"}
def transform(parent_key, parent_key_with_index):
indexes_in_parent_key = re.findall(r'\[(.*?)\]', parent_key_with_index)
target_list = predefined_mapping[parent_key].split(":")
t = []
i = 0
for elem in target_list:
try:
sub_result = re.subn(r'\[(.*?)\]', '[{}]'.format(indexes_in_parent_key[i]), elem)
if sub_result[1] > 0:
i += 1
new_elem = sub_result[0]
except IndexError as e:
new_elem = elem
t.append(new_elem)
print ":".join(t)
transform("key1:key2[]:key3[]:key4", "key1:key2[2]:key3[3]:key4")
prints newKey1[2]:newKey2[3]:newKey3 as the result.
Can someone suggest a better and elegant solution (around the usage of regex especially)?
Thanks!
You can do it a bit more elegantly by simply splitting the mapped structure on [], then interspersing the indexes from the actual data and, finally, joining everything together:
import itertools
# split the map immediately on [] so that you don't have to split each time on transform
predefined_mapping = {"key1:key2[]:key3[]:key4": "newKey1[]:newKey2[]:newKey3".split("[]")}
def transform(key, source):
mapping = predefined_mapping.get(key, None)
if not mapping: # no mapping for this key found, return unaltered
return source
indexes = re.findall(r'\[.*?\]', source) # get individual indexes
return "".join(i for e in itertools.izip_longest(mapping, indexes) for i in e if i)
print(transform("key1:key2[]:key3[]:key4", "key1:key2[2]:key3[3]:key4"))
# newKey1[2]:newKey2[3]:newKey3
NOTE: On Python 3 use itertools.zip_longest() instead.
I still think you're over-engineering this and that there is probably a much more elegant and far less error-prone approach to the whole problem. I'd advise stepping back and looking at the bigger picture instead of hammering out this particular solution just because it seems to be addressing the immediate need.

Which way is better to skip the 'NoneType' variable?

A list contains several NoneType elements. To skip the NoneType,
for item in list :
if item is not None :
fp.write(item + '\n')
#OR
for item in list :
try :
fp.write(item + '\n')
except :
pass
Which one is better and why?
As a general rule of thumb, you should not really be using the try: except: pattern for control flow if you can help it. There is some overhead involved with raising an exception that is unnecessary in this context. Hope this helps.
As people mentioned in the comment the try approach is not the good way, because you might skip an element because of any other exceptions that rise in that block.
So the first option is better. Here is an alternative, where you can be sure that all elements are not None, but it will consume more memory:
for item in (element for element in list if element is not None):
fp.write(item + '\n')
P.S. do not use built-in names as variable names, in your case - list.
The second won't be good as it will throw an exception whenever a None type element is encountered. Exception will handled in it's own way in python .
In your case you are giving a pass , so that will be done .
A more cleanest way would be :
clean = [x for x in lis if x != None]
or As pointed in the comments you could also use is not, even if it essentially compiles to the same bytecode:
clean = [x for x in lis if x is not None]
Hope this helps . When in rome do like Romans :)

Python : is there an alternate to: "except IndexError:" something lighter?

If mysql has no output...
if record[0][0]:
will return an error
IndexError: tuple index out of range
the only solution i know to fix this issue is:
try:
if record[0][0]:
# Do stuff
except IndexError:
pass
but this looks like a very heavy wrapper script
only to find out if
record[0][0]
has no data. ( no value )
is there something lighter that can be done such as..
if record[0][0] = ""
?
UPDATE:
This is my MYSQL code:
a = _mysql.escape_string(a)
db=b()
db.query("select * from b where a='" + a + "' limit 1")
result = db.store_result()
record = result.fetch_row()
UPDATE:
turns out what worked is:
if record:
rather than
if record[0]:
or
if record[0][0]:
In the general case, if you want to check if an item exists in a list, just check that it exists. Exceptions are considered Pythonic code. Using another construct for access checking is likely to be less readable and suffer from performance problems.
However, if you're really interested in something else.. how about this?
>>> if record[0]:
... field = record[0][0]
This works because an empty list ([]) evaluates as False in an if statement.
>>> record = [[]]
>>> if record[0]: # returns an empty list, e.g. []
... field = record[0][0] # is not executed
A simpler alternative:
import MySQLdb
conn = MySQLdb.connect(passwd="sekret",db="foo")
cur = conn.cursor()
cur.execute("select * from b where a=%s limit 1", (a,))
for result in cur:
print(result)
Note the changes:
Use MySQLdb, not the underlying _mysql* API
Don't concatenate variables into SQL query strings, this will lead to SQL injection.
Iterate over the cursor to get the results
In Python, there is a way to get a default value from a dict but not from a list. E.g. in a dict:
x = mydict.get('key') # x will be None if there is no 'key'
(you can also provide a different default as a 2nd arg to get() method)
Now, it would be convenient to have something like that for lists. Getting an item from a list
is in some ways very similar to getting an item from a dict, but not exactly the same. Python
made a design decision to not have a similar method for lists.
Of course, you can make your own very easily. I sometimes use a function in my own library
called 'getitem', which returns a default arg; however it only looks up one level of a list,
because I feel multiple levels is too much of a corner case and it's probably worth using
an exception with multiple levels. But, for one level you can do:
def getitem(seq, index, default=None):
"""Get item from a `seq` at `index`, return default if index out of range."""
try : return seq[index]
except IndexError : return default
Note that there's a gotcha: you can't assume that getting None back means there is no
item, if your list may itself contain None values. Seems obvious but that's something
you have to remember.
You can easily extend this function to accept multiple indexes and handle multiple
levels of lists, but then you may ask: how do I know at which level there was an
IndexError?

Remove Duplicate Items in Dictionary

I'm trying to remove duplicate items in a list through a dictionary:
def RemoveDuplicates(list):
d = dict()
for i in xrange(0, len(list)):
dict[list[i]] = 1 <------- error here
return d.keys()
But it is raising me the following error:
TypeError: 'type' object does not support item assignment
What is the problem?
You should have written:
d[list[i]] = 1
But why not do this?
def RemoveDuplicates(l):
return list(set(l))
Also, don't use built-in function names as variable names. It can lead to confusing bugs.
In addition to what others have said, it is unpythonic to do this:
for i in xrange(0, len(lst)):
do stuff with lst[i]
when you can do this instead:
for item in lst:
do stuff with item
dict is the type, you mean d[list[i]] = 1.
Addition: This points out the actual error in your code. But the answers provided by others provide better way to achieve what you are aiming at.
def remove_duplicates(myList):
return list (set(myList))
From looking at your code it seems that you are not bothered about the ordering of elements and concerned only about the uniqueness. In such a case, a set() could be a better data structure.
The problem in your code is just to use a function argument name which is not the name of the built-in type list and later on the type dict in the expression dict[list[i]].
Note that using list(set(seq)) will likely change the ordering of the remaining items. If retaining their order is important, you need to make a copy of the list:
items = set()
copy = []
for item in seq:
if not item in items:
copy.add(item)
items.append(item)
seq = copy

Categories