5

I'm using python2.7 and I was wondering what the reasoning is behind pythons string interpolation with tuples. I was getting caught up with TypeErrors when doing this small bit of code:

def show(self):
    self.score()
    print "Player has %s and total %d." % (self.player,self.player_total)
    print "Dealer has %s showing." % self.dealer[:2]

Prints:

Player has ('diamond', 'ten', 'diamond', 'eight') and total 18
Traceback (most recent call last):
File "trial.py", line 43, in <module>
    Blackjack().player_options()
  File "trial.py", line 30, in player_options
    self.show()
  File "trial.py", line 27, in show
    print "Dealer has %s showing." % (self.dealer[:2])
TypeError: not all arguments converted during string formatting

So I found that I needed to change the fourth line where the error was coming from, to this:

print "Dealer has %s %s showing." % self.dealer[:2]

With two %s operators, one for each item in the tuple slice. When I was checking out what was going on with this line though I added in a print type(self.dealer[:2]) and would get:

<type 'tuple'> 

Like I expected, why would a non-sliced tuple like the Player has %s and total %d." % (self.player,self.player_total) format fine and a sliced tuple self.dealer[:2] not? They're both the same type why not pass the slice without explicitly formatting every item in the slice?

3 Answers 3

6

String interpolation requires a format code for each element of the tuple argument. You could instead use the new .format method of strings:

>>> dealer = ('A','J','K')
>>> print 'Dealer has {} showing'.format(dealer[:2])
Dealer has ('A', 'J') showing

But note that with one argument you get the string representation of the tuple printed, along with parentheses and commas. You can use tuple unpacking to send the arguments separately, but then you need two format placeholders.

>>> print 'Dealer has {} {} showing'.format(*dealer[:2])
Dealer has A J showing

As of Python 3.6, there are f-strings. Expressions can be placed into the curly braces:

>>> dealer = ('A','J','K')
>>> print(f'Dealer has {dealer[0]} {dealer[1]} showing')
Dealer has A J showing
Sign up to request clarification or add additional context in comments.

2 Comments

What you've put up with the .format is the usual way to do this with Python3, right?
Yes, but it was backported to Python 2.6 and above as well. The early versions (3.0 and 2.6, I believe} don't support {} but rather {0} to indicate positional argument placement. .format is preferred in new code.
5

Nothing is wrong with the slice. You would get the same error when passing a tuple literal with incorrect number of elements.

"Dealer has %s showing." % self.dealer[:2]

is the same as:

"Dealer has %s showing." % (self.dealer[0], self.dealer[1])

Which is obviously an error.

So, if you would like to format self.dealer[:2] without tuple unpacking:

"Dealer has %s showing." % (self.dealer[:2],)

2 Comments

This makes sense thank you. I was misunderstanding what was going on. I thought that when passing the tuple slice that is was a smaller whole tuple not two separate arguments being passed. That is what was going on, correct?
You never pass "two separate arguments". Syntactically "string" % (foo,bar) is an expression containing % binary operator with two literal operands - a string and a tuple. Even in the famous pythonic a,b=b,a you operate with tuples. String interpolation is just a % operator overloaded for strings.
3

Your error is stemming from the fact that in the second formatting operation, you're passing the incorrect number of arguments.

Do

"dealer has %s %s showing" % self.dealer[:2]

or

"dealer has %s showing" % list(self.dealer[:2])

or

"dealer has %s showing" % self.dealer[0] #or self.dealer[1]

It has nothing to do with not using a tuple literal.

1 Comment

When you first posted, the TypeError about the number of arguments and your comment, I still wasn't getting that the tuple slice was broken down to two separate arguments not a 'whole' tuple slice. I finally realized my mistake when @Eldar Abusalimov posted.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.