List comprehension and simplifying code - python

I use Python/MySQLdb frequently and often format a list of categories for MySQL. The below code turns a list of categories into 'ADD COLUMN a FLOAT, ADD COLUMN b FLOAT, ADD COLUMN c FLOAT'. I want to figure out how best to simplify this piece of code, allowing for arbitrary change to generic string 's' (e.g. 'ADD COLUMN %s FLOAT' could easily be '%s = %d' or "%s = '%s'"). Is there some form of list comprehension which works?
categories = ['a','b','c']
select_l = []
for cat in categories:
s = 'ADD COLUMN %s FLOAT' % (cat)
select_l.append(s)
select_s = ", ".join(select_l)
I could create a method, but there seems to many examples where it wouldn't handle a specific need. Thanks

Using a generator expression, this can be written as a one-liner:
select_s = ", ".join('ADD COLUMN %s FLOAT' % cat for cat in categories)

Related

What's the difference between using a variable or %s in Python string formatting?

What is the difference between defining a variable and using it in a string and putting %s in a string and passing in the value after?
site = "Stackoverflow"
site + " is great!"
"%s is great!" % "Stackoverflow"
Printing either of these gives the same result so when is it better to use one over the other?
If you want to keep certain string constants in the same file, or on the top most of the file, you can declare the string with the placeholders as constants, then replace the placeholders with actual variable at run time through the % syntax.
This also allows greater re-usability.
Eg. you can store a single constant "%s is %s years old".
Using this syntax might also make the string more readable.
For two strings, there is little difference.
For multiple strings, s1 + s2 + s3 is less efficient, as it has to create a temporary str object for the first concatenation, where as both "%s %s %s" % (s1, s2, s3) and "{} {} {}".format(s1, s2, s3) creates the final str object immediately.
One:
'string' + 'string'
Two:
'%s %s' % ('one', 'two')
'{} {}'.format('one', 'two')
There is a great article on this here: https://pyformat.info/
Also the docs are a great resource: https://docs.python.org/2/library/string.html#format-string-syntax
Version one is less efficient with larger amounts of concatenation.

Cleaning up sqlite query in Python

Trying to self teach Python and Sqlite and my head is spinning. How does one 'clean up' the output of a query to get rid of all the brackets, commas, etc... from the result. Would also like to .title() the 2nd column. For example:
def get_all_bdays(self):
print("\n" * 100)
print("The birthdays we know about are: ")
self.c.execute('SELECT * FROM birthdays')
for row in self.c.fetchall():
print(row)
Results in the following output:
The birthdays we know about are:
(1, 'joe smoe', '12-12-1212')
How does one go about reformatting that mess to something like:
The birthdays we know about are:
1. Joe Smoe 12-12-1212
My end goal is to create an inventory system for my small business that my employees can use to find where backstock items are located in my storeroom. Thinking about using Flask for something like that, but I'm a long way off from that point in time.
Each row is a tuple with three values: the number, name, and birthday. print(row) is outputting the tuple, with all its parentheses and quotes, not any formatted version.
In Python, you can deconstruct the tuple and assign the parts of it to different variables, then format using Python's syntax for printf-like formatting:
for row in self.c.fetchall():
number, name, date = row
print("%d. %s on %s" % (number, name.title(), date))
or even:
for number, name, date in self.c.fetchall:
print("%d. %s on %s" % (number, name.title(), date))
When you print(row) you are getting the Python representation of row, which includes the quotes and commas and such. What you want to do is to str.format the data into whatever shape you like:
fmt = "{0}. {1}, on {2}"
for row in self.c.fetchall():
print(fmt.format(*row))

Django MySQL query output error while passing parameters

cur=connection.cursor()
def fillDoctors(key_bodyloc,proportion):
bodyloc_specialty_query="select distinct Speciality from body_speciality where body_location in (%s) "
#cur.execute(bodyloc_specialty_query)
data1=([key_bodyloc])
#print(bodyloc_specialty_query,data)
cur.execute(bodyloc_specialty_query,data1)
results=cur.fetchall()
specialities=[x[0] for x in results]
condition=""
for speciality in specialities:
print(str(speciality))
condition=condition+"'%"+speciality+"%'"+" or Speciality like "
#print(speciality)
#print(condition)
specialty_doctors_query="select DoctorName,Speciality,ClinicName from Doctors where Speciality like %s limit %s"
data2=([condition,proportion])
print(specialty_doctors_query,data2)
cur.execute(specialty_doctors_query,data2)
final=cur.fetchall()
print(final)
The line final=cur.fetchall() returns an empty tuple in each iteration. I've verified that the table Doctors isn't empty and the code works fine when the 'condition' is hard-coded. The code is supposed to print the doctor details for each speciality. Can anyone tell me why this is happening ?
Seems to me you are not passing your data1 into bodyloc_specialty_query properly when calling cur.execute(bodyloc_specialty_query,data1) and it causes the problem.
The syntax of string injection in Python is the following:
str1 = "some string %s" % "other string"
Instead of this way of adding a string to a string, use Pythons format builtin function:
str1 = "some string {str2}".format(str2="other_string").
But make sure that your str2 is a string or convertable to string.
I can see your data1 is a list, not str. You should convert it to str first. Good luck.
The whole point of passing in parameters to the execute method is that they get escaped. So, your condition is treated as a single string, rather than a series of parameters joined by SQL. Also, you can't use a parameter for the LIMIT value.
You need to build up some SQL and placeholders by interpolation, then just pass the values.
like = "speciality LIKE %%%s%%"
condition = like + (" OR {}".format(like)) * len(specialities)
query = "select DoctorName,Speciality,ClinicName from Doctors where {} LIMIT {}".format(condition, proportion)
cursor.execute(query, specialities)
for speciality in specialities:
condition=condition+"'%"+speciality+"%'"+" or Speciality like "

Concatenate string with array values

I'm using Python and want to be able to create an array and then concatenate the values with a string in a certain format. I'm hoping below will explain what I mean.
name_strings = ['Team 1', 'Team 2']
print "% posted a challenge to %s", %(name_strings)
Where each value from name_strings will be placed in the %s spot. Any help is much appreciated.
One way might be to expand the array in to the str format function...
array_of_strings = ['Team1', 'Team2']
message = '{0} posted a challenge to {1}'
print(message.format(*array_of_strings))
#> Team1 posted a challenge to Team2
You're very close, all you need to do is remove the comma in your example and cast it to a tuple:
print "%s posted a challenge to %s" % tuple(name_strings)
Edit: Oh, and add that missing s in %s as #falsetru pointed out.
Another way of doing it, without casting to tuple, is through use of the format function, like this:
print("{} posted a challenge to {}".format(*name_strings))
In this case, *name_strings is the python syntax for making each element in the list a separate argument to the format function.
Remove ,:
print "% posted a challenge to %s", %(name_strings)
# ^
The format specifier is incomplete. Replace it with %s.
print "% posted a challenge to %s" %(name_strings)
# ^
String formatting operation require a tuple, not a list : convert the list to a tuple.
name_strings = ['Team 1', 'Team 2']
print "%s posted a challenge to %s" % tuple(name_strings)
If you are using Python 3.x, print should be called as function form:
print("%s posted a challenge to %s" % tuple(name_strings))
Alternative using str.format:
name_strings = ['Team 1', 'Team 2']
print("{0[0]} posted a challenge to {0[1]}".format(name_strings))
concatenated_value = ' posted a challenge to '.join(name_strings)

Printing named tuples

In Python 2.7.1 I can create a named tuple:
from collections import namedtuple
Test = namedtuple('Test', ['this', 'that'])
I can populate it:
my_test = Test(this=1, that=2)
And I can print it like this:
print(my_test)
Test(this=1, that=2)
but why can't I print it like this?
print("my_test = %r" % my_test)
TypeError: not all arguments converted during string formatting
Edit:
I should have known to look at Printing tuple with string formatting in Python
Since my_test is a tuple, it will look for a % format for each item in the tuple. To get around this wrap it in another tuple where the only element is my_test:
print("my_test = %r" % (my_test,))
Don't forget the comma.
You can do this:
>>> print("my_test = %r" % str(my_test))
my_test = 'Test(this=1, that=2)'
It's unpacking it as 2 arguments. Compare with:
print("dummy1 = %s, dummy2 = %s" % ("one","two"))
In your case, try putting it in a tuple.
print("my_test = %r" % (my_test,))
The earlier answers are valid but here's an option if you don't care to print the name. It's a one-liner devised to pretty print only the contents of a named tuple of arbitrary length. Given a named tuple assigned to "named_tuple" the below yields a comma-delineated string of key=value pairs:
', '.join(['{0}={1}'.format(k, getattr(named_tuple, k)) for k in named_tuple._fields])
As now documented at 4.7.2. printf-style String Formatting, the % string formatting or interpolation operator is problematic:
The [printf-style string formatting operations] exhibit a variety of quirks that lead to a number of common errors (such as failing to display tuples and dictionaries correctly). Using the newer formatted string literals or the str.format() interface helps avoid these errors
So for example you can now do:
from collections import namedtuple
Test = namedtuple('Test', ['this', 'that'])
my_test = Test(this=1, that=2)
print("my_test = {0!r}".format(my_test))

Categories