Python Unpack Argument List for Format String - python

I have a format string that I am creating dynamically based on user input. I am collecting the arguments for the format string in a list, and I'd like to know how to unpack them at the end of the format string. I've seen some questions that seem related to this, but I'm very new to Python and I can't seem to apply their solutions to my case.
The idea of what I'd like to do is:
my_string = "string contents" % tuple([for item in var_array])
Of course this isn't valid syntax but hopefully it describes what I am trying to do: I'd like to unpack var_array as my list of arguments without knowing the length of var_array ahead of time. How could I do this?
Edit:
I'll attempt to better explain my problem. I'm creating a format string by concatenating an unknown number of format strings. Thus my final string will have a a variable number of %s and therefore a variable number of args that are collected in a list.
For example:
"My format string might have %s or %s arguments" %([arg_list]) //here arg_list has 2 arguments
"But my format string might also have %s or %s or %s arguments. %([arg_list]) //here arg_list has 3 arguments
The length of the format string, and the number of arguments are variable based on user input so I want to be able to tack on a list of args at the end of the final string. Is this possible?

Here is an approach that goes from arguments to a formatted string (error checking is still needed):
>>> def StartDance(*args):
return "%d, %d, %d, %d!" % tuple(args)
>>> StartDance(5, 6, 7, 8)
'5, 6, 7, 8!'
Here is a more robust solution to error checking but I'm presenting it as a separate answer considering how much extra complexity it is adding:
>>> def StartDance(*args):
return (", ".join(["%d"] * len(args))+"!") % tuple(args)
>>> StartDance(5, 6, 7, 8)
'5, 6, 7, 8!'
>>> StartDance(5, 6, 7, 8, 9, 10)
'5, 6, 7, 8, 9, 10!'
>>> StartDance(1)
'1!'
And here is a function returning a list which is being unpacked as arguments only to have these arguments treated as a list (Python is fun :)
>>> StartDance(*range(5,9))
'5, 6, 7, 8!'

Assuming what you want to make into a string supports the str builtin, you can do:
def join_args(*args):
return " ".join([str(x) for x in args])
print(join_args(1,2,3,4,5,6))
print(join_args('1','2','3','4'))
Out:
1 2 3 4 5 6
1 2 3 4
You could also use the following for a more flexible string:
def join_args(fmstr, *args):
return fmstr.format(*args)
print(join_args("One: {} Two: {} Three: {} Four: {}", 1,2,3,4))
Out:
One: 1 Two: 2 Three: 3 Four: 4
Just make sure there are an equal number of args and {}.

You're very close, try something like this:
"%s my %s is %s" % tuple(["Hi", "name", "butch"])

Related

How can I explode a tuple so that it can be passed as a parameter list?

Let's say I have a method definition like this:
def myMethod(a, b, c, d, e)
Then, I have a variable and a tuple like this:
myVariable = 1
myTuple = (2, 3, 4, 5)
Is there a way I can pass explode the tuple so that I can pass its members as parameters? Something like this (although I know this won't work as the entire tuple is considered the second parameter):
myMethod(myVariable, myTuple)
I'd like to avoid referencing each tuple member individually if possible...
You are looking for the argument unpacking operator *:
myMethod(myVariable, *myTuple)
From the Python documentation:
The reverse situation occurs when the
arguments are already in a list or
tuple but need to be unpacked for a
function call requiring separate
positional arguments. For instance,
the built-in range() function expects
separate start and stop arguments. If
they are not available separately,
write the function call with the
*-operator to unpack the arguments out of a list or tuple:
>>> range(3, 6) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> range(*args) # call with arguments unpacked from a list
[3, 4, 5]
In the same fashion, dictionaries can
deliver keyword arguments with the
**-operator:
>>> def parrot(voltage, state='a stiff', action='voom'):
... print "-- This parrot wouldn't", action,
... print "if you put", voltage, "volts through it.",
... print "E's", state, "!"
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !

Append a tuple to a list

Given a tuple (specifically, a functions varargs), I want to prepend a list containing one or more items, then call another function with the result as a list. So far, the best I've come up with is:
def fn(*args):
l = ['foo', 'bar']
l.extend(args)
fn2(l)
Which, given Pythons usual terseness when it comes to this sort of thing, seems like it takes 2 more lines than it should. Is there a more pythonic way?
You can convert the tuple to a list, which will allow you to concatenate it to the other list. ie:
def fn(*args):
fn2(['foo', 'bar'] + list(args))
If your fn2 took varargs also, you wouldn't need to build the combined list:
def fn2(*l):
print l
def fn(*args):
fn2(1, 2, *args)
fn(10, 9, 8)
produces
(1, 2, 10, 9, 8)

Printing tuple with string formatting in Python

So, i have this problem.
I got tuple (1,2,3) which i should print with string formatting.
eg.
tup = (1,2,3)
print "this is a tuple %something" % (tup)
and this should print tuple representation with brackets, like
This is a tuple (1,2,3)
But I get TypeError: not all arguments converted during string formatting instead.
How in the world am I able to do this? Kinda lost here so if you guys could point me to a right direction :)
>>> # Python 2
>>> thetuple = (1, 2, 3)
>>> print "this is a tuple: %s" % (thetuple,)
this is a tuple: (1, 2, 3)
>>> # Python 3
>>> thetuple = (1, 2, 3)
>>> print(f"this is a tuple: %s" % (thetuple,))
this is a tuple: (1, 2, 3)
Making a singleton tuple with the tuple of interest as the only item, i.e. the (thetuple,) part, is the key bit here.
Note that the % syntax is obsolete. Use str.format, which is simpler and more readable:
t = 1,2,3
print 'This is a tuple {0}'.format(t)
Many answers given above were correct. The right way to do it is:
>>> thetuple = (1, 2, 3)
>>> print "this is a tuple: %s" % (thetuple,)
this is a tuple: (1, 2, 3)
However, there was a dispute over if the '%' String operator is obsolete. As many have pointed out, it is definitely not obsolete, as the '%' String operator is easier to combine a String statement with a list data.
Example:
>>> tup = (1,2,3)
>>> print "First: %d, Second: %d, Third: %d" % tup
First: 1, Second: 2, Third: 3
However, using the .format() function, you will end up with a verbose statement.
Example:
>>> tup = (1,2,3)
>>> print "First: %d, Second: %d, Third: %d" % tup
>>> print 'First: {}, Second: {}, Third: {}'.format(1,2,3)
>>> print 'First: {0[0]}, Second: {0[1]}, Third: {0[2]}'.format(tup)
First: 1, Second: 2, Third: 3
First: 1, Second: 2, Third: 3
First: 1, Second: 2, Third: 3
Further more, '%' string operator also useful for us to validate the data type such as %s, %d, %i, while .format() only support two conversion flags: '!s' and '!r'.
>>> tup = (1, 2, 3)
>>> print "Here it is: %s" % (tup,)
Here it is: (1, 2, 3)
>>>
Note that (tup,) is a tuple containing a tuple. The outer tuple is the argument to the % operator. The inner tuple is its content, which is actually printed.
(tup) is an expression in brackets, which when evaluated results in tup.
(tup,) with the trailing comma is a tuple, which contains tup as is only member.
Even though this question is quite old and has many different answers, I'd still like to add the imho most "pythonic" and also readable/concise answer.
Since the general tuple printing method is already shown correctly by Antimony, this is an addition for printing each element in a tuple separately, as Fong Kah Chun has shown correctly with the %s syntax.
Interestingly it has been only mentioned in a comment, but using an asterisk operator to unpack the tuple yields full flexibility and readability using the str.format method when printing tuple elements separately.
tup = (1, 2, 3)
print('Element(s) of the tuple: One {0}, two {1}, three {2}'.format(*tup))
This also avoids printing a trailing comma when printing a single-element tuple, as circumvented by Jacob CUI with replace. (Even though imho the trailing comma representation is correct if wanting to preserve the type representation when printing):
tup = (1, )
print('Element(s) of the tuple: One {0}'.format(*tup))
This doesn't use string formatting, but you should be able to do:
print 'this is a tuple ', (1, 2, 3)
If you really want to use string formatting:
print 'this is a tuple %s' % str((1, 2, 3))
# or
print 'this is a tuple %s' % ((1, 2, 3),)
Note, this assumes you are using a Python version earlier than 3.0.
t = (1, 2, 3)
# the comma (,) concatenates the strings and adds a space
print "this is a tuple", (t)
# format is the most flexible way to do string formatting
print "this is a tuple {0}".format(t)
# classic string formatting
# I use it only when working with older Python versions
print "this is a tuple %s" % repr(t)
print "this is a tuple %s" % str(t)
Besides the methods proposed in the other answers, since Python 3.6 you can also use Literal String Interpolation (f-strings):
>>> tup = (1,2,3)
>>> print(f'this is a tuple {tup}')
this is a tuple (1, 2, 3)
I think the best way to do this is:
t = (1,2,3)
print "This is a tuple: %s" % str(t)
If you're familiar with printf style formatting, then Python supports its own version. In Python, this is done using the "%" operator applied to strings (an overload of the modulo operator), which takes any string and applies printf-style formatting to it.
In our case, we are telling it to print "This is a tuple: ", and then adding a string "%s", and for the actual string, we're passing in a string representation of the tuple (by calling str(t)).
If you're not familiar with printf style formatting, I highly suggest learning, since it's very standard. Most languages support it in one way or another.
Please note a trailing comma will be added if the tuple only has one item. e.g:
t = (1,)
print 'this is a tuple {}'.format(t)
and you'll get:
'this is a tuple (1,)'
in some cases e.g. you want to get a quoted list to be used in mysql query string like
SELECT name FROM students WHERE name IN ('Tom', 'Jerry');
you need to consider to remove the tailing comma use replace(',)', ')') after formatting because it's possible that the tuple has only 1 item like ('Tom',), so the tailing comma needs to be removed:
query_string = 'SELECT name FROM students WHERE name IN {}'.format(t).replace(',)', ')')
Please suggest if you have decent way of removing this comma in the output.
For python 3
tup = (1,2,3)
print("this is a tuple %s" % str(tup))
Try this to get an answer:
>>>d = ('1', '2')
>>> print("Value: %s" %(d))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting
If we put only-one tuple inside (), it makes a tuple itself:
>>> (d)
('1', '2')
This means the above print statement will look like:
print("Value: %s" %('1', '2')) which is an error!
Hence:
>>> (d,)
(('1', '2'),)
>>>
Above will be fed correctly to the print's arguments.
You can try this one as well;
tup = (1,2,3)
print("this is a tuple {something}".format(something=tup))
You can't use %something with (tup) just because of packing and unpacking concept with tuple.
Using f-string for a quick print in python3.
tup = (1,2,3)
print(f"this is a tuple {tup}")
how much changed over the years. Now you can do this:
tup = (1,2,3)
print(f'This is a Tuple {tup}.')
Results in: This is a Tuple (1,2,3).
Talk is cheap, show you the code:
>>> tup = (10, 20, 30)
>>> i = 50
>>> print '%d %s'%(i,tup)
50 (10, 20, 30)
>>> print '%s'%(tup,)
(10, 20, 30)
>>>

Passing functions which have multiple return values as arguments in Python

So, Python functions can return multiple values. It struck me that it would be convenient (though a bit less readable) if the following were possible.
a = [[1,2],[3,4]]
def cord():
return 1, 1
def printa(y,x):
print a[y][x]
printa(cord())
...but it's not. I'm aware that you can do the same thing by dumping both return values into temporary variables, but it doesn't seem as elegant. I could also rewrite the last line as "printa(cord()[0], cord()[1])", but that would execute cord() twice.
Is there an elegant, efficient way to do this? Or should I just see that quote about premature optimization and forget about this?
printa(*cord())
The * here is an argument expansion operator... well I forget what it's technically called, but in this context it takes a list or tuple and expands it out so the function sees each list/tuple element as a separate argument.
It's basically the reverse of the * you might use to capture all non-keyword arguments in a function definition:
def fn(*args):
# args is now a tuple of the non-keyworded arguments
print args
fn(1, 2, 3, 4, 5)
prints (1, 2, 3, 4, 5)
fn(*[1, 2, 3, 4, 5])
does the same.
Try this:
>>> def cord():
... return (1, 1)
...
>>> def printa(y, x):
... print a[y][x]
...
>>> a=[[1,2],[3,4]]
>>> printa(*cord())
4
The star basically says "use the elements of this collection as positional arguments." You can do the same with a dict for keyword arguments using two stars:
>>> a = {'a' : 2, 'b' : 3}
>>> def foo(a, b):
... print a, b
...
>>> foo(**a)
2 3
Actually, Python doesn't really return multiple values, it returns one value which can be multiple values packed into a tuple. Which means that you need to "unpack" the returned value in order to have multiples.
A statement like
x,y = cord()
does that, but directly using the return value as you did in
printa(cord())
doesn't, that's why you need to use the asterisk. Perhaps a nice term for it might be "implicit tuple unpacking" or "tuple unpacking without assignment".

How do I do what strtok() does in C, in Python?

I am learning Python and trying to figure out an efficient way to tokenize a string of numbers separated by commas into a list. Well formed cases work as I expect, but less well formed cases not so much.
If I have this:
A = '1,2,3,4'
B = [int(x) for x in A.split(',')]
B results in [1, 2, 3, 4]
which is what I expect, but if the string is something more like
A = '1,,2,3,4,'
if I'm using the same list comprehension expression for B as above, I get an exception. I think I understand why (because some of the "x" string values are not integers), but I'm thinking that there would be a way to parse this still quite elegantly such that tokenization of the string a works a bit more directly like strtok(A,",\n\t") would have done when called iteratively in C.
To be clear what I am asking; I am looking for an elegant/efficient/typical way in Python to have all of the following example cases of strings:
A='1,,2,3,\n,4,\n'
A='1,2,3,4'
A=',1,2,3,4,\t\n'
A='\n\t,1,2,3,,4\n'
return with the same list of:
B=[1,2,3,4]
via some sort of compact expression.
How about this:
A = '1, 2,,3,4 '
B = [int(x) for x in A.split(',') if x.strip()]
x.strip() trims whitespace from the string, which will make it empty if the string is all whitespace. An empty string is "false" in a boolean context, so it's filtered by the if part of the list comprehension.
Generally, I try to avoid regular expressions, but if you want to split on a bunch of different things, they work. Try this:
import re
result = [int(x) for x in filter(None, re.split('[,\n,\t]', A))]
Mmm, functional goodness (with a bit of generator expression thrown in):
a = "1,2,,3,4,"
print map(int, filter(None, (i.strip() for i in a.split(','))))
For full functional joy:
import string
a = "1,2,,3,4,"
print map(int, filter(None, map(string.strip, a.split(','))))
For the sake of completeness, I will answer this seven year old question:
The C program that uses strtok:
int main()
{
char myLine[]="This is;a-line,with pieces";
char *p;
for(p=strtok(myLine, " ;-,"); p != NULL; p=strtok(NULL, " ;-,"))
{
printf("piece=%s\n", p);
}
}
can be accomplished in python with re.split as:
import re
myLine="This is;a-line,with pieces"
for p in re.split("[ ;\-,]",myLine):
print("piece="+p)
This will work, and never raise an exception, if all the numbers are ints. The isdigit() call is false if there's a decimal point in the string.
>>> nums = ['1,,2,3,\n,4\n', '1,2,3,4', ',1,2,3,4,\t\n', '\n\t,1,2,3,,4\n']
>>> for n in nums:
... [ int(i.strip()) for i in n if i.strip() and i.strip().isdigit() ]
...
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
How about this?
>>> a = "1,2,,3,4,"
>>> map(int,filter(None,a.split(",")))
[1, 2, 3, 4]
filter will remove all false values (i.e. empty strings), which are then mapped to int.
EDIT: Just tested this against the above posted versions, and it seems to be significantly faster, 15% or so compared to the strip() one and more than twice as fast as the isdigit() one
Why accept inferior substitutes that cannot segfault your interpreter? With ctypes you can just call the real thing! :-)
# strtok in Python
from ctypes import c_char_p, cdll
try: libc = cdll.LoadLibrary('libc.so.6')
except WindowsError:
libc = cdll.LoadLibrary('msvcrt.dll')
libc.strtok.restype = c_char_p
dat = c_char_p("1,,2,3,4")
sep = c_char_p(",\n\t")
result = [libc.strtok(dat, sep)] + list(iter(lambda: libc.strtok(None, sep), None))
print(result)
Why not just wrap in a try except block which catches anything not an integer?
I was desperately in need of strtok equivalent in Python. So I developed a simple one by my own
def strtok(val,delim):
token_list=[]
token_list.append(val)
for key in delim:
nList=[]
for token in token_list:
subTokens = [ x for x in token.split(key) if x.strip()]
nList= nList + subTokens
token_list = nList
return token_list
I'd guess regular expressions are the way to go: http://docs.python.org/library/re.html

Categories