开发者

String concatenation in Python and commas

I'm having a hard time figuring out how the native data types interact in Python. Here, I am trying to concatenate different parts of the lyrics into one long string which will be returned as output.

The error I receive upon trying run the script is:

TypeError: cannot concatenate 'str' and 'tuple' objects.

I put everything that wasn't a string in the function str(), but apparently something is still a "tuple" (a data type I've never used before).

How can I get whatever tuple is in there to a string so this will all concatenate smoothly?

(P.S.: I used the variable "Copy", because I wasn't sure if, when I decremented the other variable, it would mess with the for loop construct. Would it?)

#99 bottles of beer on the wall lyrics

def BottlesOfBeerLyrics(NumOfBottlesOfBeer = 99):
        BottlesOfBeer = NumOfBottlesOfBeer
        Copy = BottlesOfBeer
        Lyrics = ''

        for i in range(Copy):
                Lyrics += BottlesOfBeer, " bottles of beer on the wall, ", str(BottlesOfBeer), " bottles of beer. \n", \
                "Take one down and开发者_如何学Go pass it around, ", str(BottlesOfBeer - 1), " bottles of beer on the wall. \n"

                if (BottlesOfBeer > 1):
                        Lyrics += "\n"

                BottlesOfBeer -= 1

        return Lyrics

print BottlesOfBeerLyrics(99)

Some people suggested building a list and the joining it. I edited it a little bit, but is this the preferred method?

#99 bottles of beer on the wall lyrics - list method

def BottlesOfBeerLyrics(NumOfBottlesOfBeer = 99):
        BottlesOfBeer = NumOfBottlesOfBeer
        Copy = BottlesOfBeer
        Lyrics = []

        for i in range(Copy):
                Lyrics += str(BottlesOfBeer) + " bottles of beer on the wall, " + str(BottlesOfBeer) + " bottles of beer. \n" + \
                "Take one down and pass it around, " + str(BottlesOfBeer - 1) + " bottles of beer on the wall. \n"

                if (BottlesOfBeer > 1):
                        Lyrics += "\n"

                BottlesOfBeer -= 1

        return "".join(Lyrics)

print BottlesOfBeerLyrics(99)


Don't use string concatenation for this. Put the strings in a list and join the list at the end. I'd also suggest using str.format.

verse = "{0} bottles of beer on the wall, {0} bottles of beer.\n" \
        "Take one down and pass it around, {1} bottles of beer on the wall.\n"

def bottles_of_beer_lyrics(bottles=99):
    lyrics = []
    for x in range(bottles, 0, -1):
        lyrics.append(verse.format(x, x-1))
    return '\n'.join(lyrics)

You could also get the result more directly by using a generator expression:

def bottles_of_beer_lyrics(bottles=99):
    return '\n'.join(verse.format(x, x-1) for x in range(bottles, 0, -1))

As a final point you should note that "1 bottles" is not grammatically correct. You may want to create a function that can give you the correct form of "bottle" depending on the number. If internationalization is an issue (I know it's probably not) then you should also be aware that some languages have more forms than just "singular" and "plural".


The comma-separated list to the left of Lyrics += is defining a "tuple".

You'll want to change the "," to "+", since string concatenation does not take a comma-separated list of values.

Also, consider building up a list of strings to concatenate and then using the "join" method.


The comma operator creates a tuple. The line "Lyrics += ..." is creating a tuple on the right side.

To concatenate strings in Python use the "+" operator.

Lyrics += str(BottlesOfBeer) + " bottles of beer..." + ...

However, that's still not the preferred way for this kind of thing, but is fine for learning string concatenation.


It looks like you've got the original problem cleared up and are now asking about using join() -- yes, that's generally a better than using += for string concatenation (although not always faster).

But even better is to not even do it or do so as little as possible. Python had something called format strings which are something like those used by C's printf() function -- see Format String Syntax in the online documentation. Using that along with the format() string method (and some other Pythonisms) can really simplify things:

def BottlesOfBeerLyrics(NumOfBottlesOfBeer=99):
    PluralSuffix = lambda n: "s" if n != 1 else ""
    Stanza = "\n".join([
        "{0} bottle{1} of beer on the wall, {0} bottle{1} of beer.",
        "Take one down and pass it around, {2} bottle{3} of beer on the wall.",
        "\n"])
    Lyrics = ""
    for Bottles in range(NumOfBottlesOfBeer, 0, -1):
        Lyrics += Stanza.format(Bottles, PluralSuffix(Bottles),
                                Bottles-1, PluralSuffix(Bottles-1))
    return Lyrics

print BottlesOfBeerLyrics(3)
# 3 bottles of beer on the wall, 3 bottles of beer.
# Take one down and pass it around, 2 bottles of beer on the wall.
#
# 2 bottles of beer on the wall, 2 bottles of beer.
# Take one down and pass it around, 1 bottle of beer on the wall.
#
# 1 bottle of beer on the wall, 1 bottle of beer.
# Take one down and pass it around, 0 bottles of beer on the wall.


Lyrics += BottlesOfBeer, " bottles of beer on the wall, ", str(BottlesOfBeer), " bottles of beer. \n", \
                "Take one down and pass it around, ", str(BottlesOfBeer - 1), " bottles of beer on the wall. \n"

The problem is everything after the += is a tuple. Change all the commas to pluses and cast the first BottlesOfBeer to string.

Lyrics += str(BottlesOfBeer) + " bottles of beer on the wall, " + str(BottlesOfBeer) + " bottles of beer. \n" + \
                "Take one down and pass it around, " + str(BottlesOfBeer - 1) + " bottles of beer on the wall. \n"

Short demonstration:

>>> a = 'hello', 'world'
>>> b = 'hello' + 'world'
>>> type(a)
<type 'tuple'>
>>> type(b)
<type 'str'>

A better way to format the string would be to use string formatters:

Lyrics += '%(orig)d bottles of beer on the wall, %(orig)d bottles of beer.\n' \
        'Take one down and pass it around, %(now)d bottles of beer on the wall.\n' % \
        { 'orig': BottlesOfBeer, 'now': BottlesOfBeer-1 }

Your variable names should start with a lower case letter, else they are easily confused with class names. Ideally though, you should follow PEP 8 and use lowercase with words separated by underscores.

You do not need the Copy variable, as a copy of BottlesOfBeer will be passed to range(). Same story with BottlesOfBeer = NumOfBottlesOfBeer, you can use and modify NumOfBottlesOfBeer throughout the function.

Since you have a default argument NumOfBottlesOfBeer = 99, you don't need to pass 99 when calling BottlesOfBeerLyrics.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜