Python oneline foreach verification in string - python

I want to be sure that none item of a list is present on a string.
At the moment I do :
presents = False
for item in item_list:
if item in string_control:
presents = True
break;
Is there a way to do it in only one line ? I really often do these types of control.

Yes :
presents = any(x in string_control for x in item_list)

I think string_control has a value something like this. presents then becomes a boolean indicating the same as in your code but most likely in most circumstances you don't need the cast to bool. I.e. this probably works fine too: presents = [i for i in item_list if i == string_control]
string_control = None
presents = bool([i for i in item_list if i == string_control])

Related

Better / More pythonic way to process the results of a function with multiple return values

The code below works, but looks very ugly. I'm looking for a more pythonic way to write the same thing.
The goal:
React on a result of a function that returns multiple values.
Example function
def myfilterfunc(mystr):
if 'la' in mystr:
return True, mystr
return False, None
This returns True and a string (if the string cointains "la"), or False and nothing.
In a second function, I'm passing myfilterfunc as an optional parameter
def mymainfunc(mystr,filterfunc=None):
This function fills a returnlist.
If no function is given, the result is not filtered and added as is.
If a filter function is given, if the filter function returns
True, a returned string is added. (This is just an example that would
easily work with one return value, but I'm trying to get the systax
right for a more complicated setup)
if filterfunc:
tmp_status,tmp_string = filterfunc(mystr[startpos:nextitem])
if tmp_status:
returnlist.append(tmp_string)
else:
returnlist.append(mystr[startpos:nextitem])
Any idea how I can write this without using temporary variables to store the return values of the function?
Full "working" test code below
def string2list(mystr,splitlist,filterfunc=None):
returnlist = []
startpos = 0
nextitem = -1
matched = True
while matched:
matched = False
for sub in splitlist:
if startpos == 0:
tmpi = mystr.find(sub)
else:
tmpi = mystr.find(sub,startpos + 1)
if (tmpi > 0) and ((nextitem < 0) or (nextitem > tmpi)):
nextitem = tmpi
matched = True
if filterfunc:
tmp_status,tmp_string = filterfunc(mystr[startpos:nextitem])
if tmp_status:
returnlist.append(tmp_string)
else:
returnlist.append(mystr[startpos:nextitem])
startpos = nextitem
nextitem = -1
return returnlist
def myfilterfunc(mystr):
if 'la' in mystr:
return True,mystr
return False,''
splitlist = ['li','la']
mytext = '''
li1
li2
li3
fg4
fg5
fg6
la7
la
la
tz
tz
tzt
tz
end
'''
print string2list(mytext,splitlist)
print
print string2list(mytext,splitlist,myfilterfunc)
If this is going to happen often you can factor out the uglyness:
def filtered(f, x):
if f:
status, result = f(x)
return result if status else x
else:
return x
used like
returnlist.append(filtered(filterfunc, mystr[startpos:nextitem]))
so that if you have many similar optional filters the code remains readable. This works because in Python functions/closures are first class citizens and you can pass them around like other values.
But then if the logic is about always adding (either the filtered or the unfiltered) why not just write the filter to return the input instead of (False, "") in case of failure?
That would make the code simpler to understand...
returnlist.append(filterfunc(mystr[startpos:nextitem]))
I think there are two better approaches to your problem that don't involve using two return values.
The first is to simply return a Boolean value and not a string at all. This works if your filter is always going to return the string it was passed unmodified if it returns a string at all (e.g. if the first value is True). This approach will let you avoid using temporary values at all:
if filterfunc:
if filterfunc(mystr[startpos:nextitem]):
returnlist.append(mystr[startpos:nextitem])
(Note, I'd suggest renaming filterfunc to predicate if you go this route.)
The other option will work if some filterfunc might return a different second value than it was passed under some situations, but never the 2-tuple True, None. In this approach you simply use the single value as both the signal and the payload. If it's None, you ignore it. If it's anything else, you use it. This does require a temporary variable, but only one (and it's a lot less ugly).
if filterfunc:
result = filterfunc(mystr[startpos:nextitem])
if result is not None:
returnlist.append(result)

Iterating over references to variables in Python

I have an object called Song, which is defined as:
class Song(object):
def __init__(self):
self.title = None
self.songauthor = None
self.textauthor = None
self.categories = None
Inside this class I have a method that parses a run-time property of that object, "metadata", which is basically just a text file with some formatted text that I parse with regular expressions. During this process, I have come up with the following code that I am pretty certain can be simplified to a loop.
re_title = re.compile("^title:(.*)$", re.MULTILINE)
re_textauthor = re.compile("^textauthor:(.*)$", re.MULTILINE)
re_songauthor = re.compile("^songauthor:(.*)$", re.MULTILINE)
re_categories = re.compile("^categories:(.*)$", re.MULTILINE)
#
# it must be possible to simplify the below code to a loop...
#
tmp = re_title.findall(self.metadata)
self.title = tmp[0] if len(tmp) > 0 else None
tmp = re_textauthor.findall(self.metadata)
self.textauthor = tmp[0] if len(tmp) > 0 else None
tmp = re_songauthor.findall(self.metadata)
self.songauthor = tmp[0] if len(tmp) > 0 else None
tmp = re_categories.findall(self.metadata)
self.categories = tmp[0] if len(tmp) > 0 else None
I'm guessing this can be done by encapsulating a reference to the property (e.g. self.title) and the corresponding regular expression (re_title) in a datatype (possibly tuple), and then iterate over a list of these data types.
I have a tried using a tuple as such:
for x in ((self.title, re_title),
(self.textauthor, re_textauthor),
(self.songauthor, re_songauthor),
(self.categories, re_categories)):
data = x[1].findall(self.metadata)
x[0] = data[0] if len(data) > 0 else None
This failed horribly as I cannot modify a tuple in run-time. Can anyone provide a suggestion as to how I can pull this off?
There are two problems with your code.
The big one is that x[0] is not a reference to self.title, it's a reference to the value of self.title. In other words, you're just copying the existing title into a tuple, then replacing that title in the tuple with a different one, which has no effect on the existing title.
The smaller one is that you can't replace elements in a tuple. You could fix that trivially by using a list instead of a tuple, but you're still going to have the big problem.
So, how do you create references to variables in Python? You can't. You need to think of a way to reorganize things. For example, maybe you can access these things by name, instead of by reference. Instead of four separate variables, store a dictionary of four variables in a single dictionary:
res = {
'title': re.compile("^title:(.*)$", re.MULTILINE),
'textauthor': re.compile("^textauthor:(.*)$", re.MULTILINE)
'songauthor': re.compile("^songauthor:(.*)$", re.MULTILINE)
'categories': re.compile("^categories:(.*)$", re.MULTILINE)
}
class Song(object):
def __init__(self):
self.properties = {}
def parsify(self, text):
for thing in ('title', 'textauthor', 'songauthor', 'categories'):
data = res[thing].findall(self.metadata)
self.properties[thing] = data[0] if len(data) > 0 else None
You could also use for thing in res: there, because that will iterate over all the keys (in arbitrary order, but you probably don't care about the order).
If you really need to have self.title, you've run into a common problem. Usually, there's a clear distinction between data—which should be referred to by runtime strings—and attributes—which should not. But sometimes, there isn't. So you have to bridge between them in some way. You can create four #property fields that return self.properties['title'], or you can use setattr(self, thing, …) instead of self.properties[thing], or various other possibilities. Which one is best comes down to whether they're more data-like or more attribute-like.
Instead of assigning to the tuple, update the class members directly:
all_res = {'title':re_title,
'textauthor': re_textauthor,
'songauthor': re_song_author,
'categories': re_categories}
for k, v in all_res.iteritems():
tmp = v.findall(self.metadata)
if tmp:
setattr(self, k, tmp[0])
else:
setattr(self, k, None)
If you only care about the first match, you don't need to use findall.
abarnert's answer has given a good explanation of what is going wrong with your code, but I wanted to offer up an alternative solution. Rather than using a loop to assign each variable, try creating an iterable of the different values from the parsed file, then use a single unpacking-assignment to get them into the various variables.
Here's a two-statement solution using a list comprehension, which is made just a bit tricky by the fact that you need to reference the result of findall twice in if/else expression (thus the nested generator expression):
vals = [x[0] if len(x) > 0 else None for x in (regex.findall(self.metadata) for regex in
[re_title, re_textauthor,
re_songauthor, re_categories])]
self.title, self.textauthor, self.songauthor, self.categories = vals
You can probably simplify things a little bit in the first part of the list comprehension. To start with, you can just test if x rather than if len(x) > 0. Or, if you're not too attached to using findall, you could use search instead, then just use x and x.group(0) instead of the whole if/else bit. The search method returns None if no match was found, so the short-circuiting behavior of the and operator will do exactly what we want.
An example would be to use a dictionary like this:
things = {}
for x in ((self.title, re_title),
(self.textauthor, re_textauthor),
(self.songauthor, re_songauthor),
(self.categories, re_categories)):
if len(x[1].findall(self.metadata):
things[x[0]] = x[1].findall(self.metadata)[1]
else:
things[x[0]] = None
Could this be a possible solution?

how to loop over each changeInfo['changeInfo'][1...x]['Url']

I have the following code snippet ,i want to change it in such a way where I want loop over for each changeInfo['changeInfo'][1..x],how can I do that
for changeInfo in MainchangeInfo:
if (changeInfo['CRStatus'] == 'Fix' and (('Not Provided' in changeInfo['changeInfo'][0]['Url'] or 'Wrong change Provided' in changeInfo['changeInfo'][0]['Url']) or 'NEW' in changeInfo['changeInfo'][0]['Status'] or 'ABANDONED' in changeInfo['changeInfo'][0]['Status'] or 'Yes' not in changeInfo['RNotesStatus'] or 'Provided' not in changeInfo['RCAInfo'] or 'False' in str(changeInfo['IsDevComplete']))):
if 'Wrong change Provided' in changeInfo['changeInfo'][0]['Url'] or changeInfo['changeInfo'][0]['Info'] != 'Available' ://want to loop over for changeInfo['changeInfo'][0]
changeMailBody = changeMailBody + "<tr bgcolor=\"Red\">"
what do you mean by [1..x]?
if you want to loop over the 'first x' elements in changeInfo['changeInfo'] (in which case, did you mean [0..x]?) you can use slice notation:
for item in changeInfo['changeInfo'][:x]:
# do stuff
if you really want from 1 to x, i.e. skipping the first element you can do:
for item in changeInfo['changeInfo'][1:x]:
# do stuff
See docs here:
http://docs.python.org/2.3/whatsnew/section-slices.html
EDIT:
After your clarification in the comment it's clear you don't even need slice notation, you just need for item in changeInfo['changeInfo'] ...I think your full example would look like:
for changeInfo in MainchangeInfo:
for item in changeInfo['changeInfo']:
if (changeInfo['CRStatus'] == 'Fix' and (('Not Provided' in item['Url'] or 'Wrong change Provided' in item['Url']) or 'NEW' in item['Status'] or 'ABANDONED' in item['Status'] or 'Yes' not in changeInfo['RNotesStatus'] or 'Provided' not in changeInfo['RCAInfo'] or 'False' in str(changeInfo['IsDevComplete']))):
if 'Wrong change Provided' in item['Url'] or item['Info'] != 'Available' ://want to loop over for changeInfo['changeInfo'][0]
changeMailBody = changeMailBody + "<tr bgcolor=\"Red\">"
You can do this with an explicit loop:
for change in changeInfo['changeInfo']:
info = change['info']
# do stuff with it
Or, if you want to write it out as a comprehension:
infos = [change['info'] for change in changeInfo['changeInfo']]
Or, if you just want an iterator, not a list:
infos = (change['info'] for change in changeInfo['changeInfo'])
In any case, you will get changeInfo['changeInfo'][0]['info'], then changeInfo['changeInfo'][1]['info'], and so on.
I'm assuming here that changeInfo['changeInfo'] is a list, not a dict whose keys happen to be small integers. If that assumption is wrong, just replace changeInfo['changeInfo'] with changeInfo['changeInfo'].values() in whichever solution you choose. (Of course in that case, the order will be arbitrary, but that's exactly what you should expect from a dict.)
So, in your existing code, instead of this:
if ('Wrong change Provided' in changeInfo['changeInfo'][0]['Url'] or
changeInfo['changeInfo'][0]['Info'] != 'Available'):
… I'd use the generator expression, together with the any function, like this:
if any('Wrong change Provided' in change['Url'] or change['Info'] != 'Available'
for change in changeInfo['changeInfo']):
Now instead of checking whether this condition is true for the first value in changeInfo['changeInfo']—that is, changeInfo['changeInfo'][0]—you're testing whether it's true for any of the values in changeInfo['changeInfo']. Which, as I understand it, is exactly what you wanted.

How to use an "or" inside a filter

I want to make a search, but I need to bring the registers that have status Canceled or modified.
I thought that this would work but It didn't
citasotras = citas_agendarcita.objects.filter(cita_agendar_status="Modificada" or "",citas_tipodepaciente="mediexcel")
In your example, The expression "Modificada" or "" evaluates to "Modificada".
>>> "Modificada" or ""
'Modificada'
Therefore, your example is as if you simply had:
citasotras = citas_agendarcita.objects.filter(cita_agendar_status="Modificada", citas_tipodepaciente="mediexcel")
You want any objects where the cita_agendar_status is equal to any of the items in the list ["Modificada", ""]. You can use __in to do this:
citasotras = citas_agendarcita.objects.filter(cita_agendar_status__in=["Modificada", ""] ,citas_tipodepaciente="mediexcel")
See the Django docs for more information.
For AND/OR conditions Q objects can be used:
citas_agendarcita.objects.filter(Q(cita_agendar_status="Modificada")|Q(cita_agendar_status=""), \
citas_tipodepaciente="mediexcel")

Should I return an empty dict instead of None?

I have a method that currently returns None or a dict.
result,error = o.apply('grammar')
The caller currently has to check for the existence of two keys to decide what kind of object was returned.
if 'imperial' in result:
# yay
elif 'west' in result:
# yahoo
else:
# something wrong?
Because result can be None, I'm thinking of returning an empty dict instead, so the caller does not need to check for that. What do you think ?
For comparison, in the re module, the result of calling match can result in None.
p = re.compile('\w+')
m = p.match( 'whatever' )
But in this case, m is an object instance. In my case, I am returning a dict which should either be empty or have some entries.
Yes I think returning an empty dict (or where applicable an empty list) is preferable to returning None as this avoids an additional check in the client code.
EDIT:
Adding some code sample to elaborate:
def result_none(choice):
mydict = {}
if choice == 'a':
mydict['x'] = 100
mydict['y'] = 1000
return mydict
else:
return None
def result_dict(choice):
mydict = {}
if choice == 'a':
mydict['x'] = 100
mydict['y'] = 1000
return mydict
test_dict = result_dict('b')
if test_dict.get('x'):
print 'Got x'
else:
print 'No x'
test_none = result_none('b')
if test_none.get('x'):
print 'Got x'
else:
print 'No x'
In the above code the check test_none.get(x) throws an AttributeError as
result_none method can possibly return a None. To avoid that I have to add an
additional check and might rewrite that line as:
if test_none is not None and test_none.get('x') which is not at all needed
if the method were returning an empty dict. As the example shows the check test_dict.get('x') works fine as the method result_dict returns an empty dict.
I'm not entirely sure of the context of this code, but I'd say returning None suggests that there was somehow an error and the operation could not be completed. Returning an empty dictionary suggests success, but nothing matched the criteria for being added to the dictionary.
I come from a completely different background (C++ Game Development) so take this for what it's worth:
For performance reasons though, might be nice to return None and save whatever overhead, though minimal, may be involved in creating an empty dictionary. I find that, generally, if you're using a scripting language, you're not concerned about the performance of that code. If you were, you probably wouldn't be writing that feature in said language unless required for some unavoidable reason.
As others have said, an empty dict is falsy, so there's no problem there. But the idea of returning an empty dict leaves a bad taste in my mouth. I can't help but feel that returning an empty dict could hide errors that returning None would reveal. Still, it's just a gut feeling.
After more thought, I think returning an empty dict might be more Pythonic. A good rule of thumb might be to always return an empty container if you write a function/method which returns a container. Several examples of this behavior:
"".split() == []
filter(lambda a:False, [1,2]) == []
range(1, -1) == []
re.findall('x', '') = []
In contrast if you are trying to get a single object, you have no choice but to return None I suppose. So I guess None is like the empty container for single objects! Thanks to KennyTM for arguing some sense into me :D
Python supports returning multiple values. Hence, you can return a status of success along with an empty dictionary. The caller first verifies the return code and then uses the dictionary.
def result_none(choice):
mydict = {}
retcode = -1
if choice == 'a':
mydict['x'] = 100
mydict['y'] = 1000
retcode = 0
return mydict, retcode
retcode, mydict = result_none('a')
if retcode == 0:
<<use dictionary>>

Categories