TypeError: sequence item 0: expected string, NoneT

2020-07-02 08:57发布

问题:

I'm trying to improve a game of battleships. The original version works fine with no errors. I have written code to help overcome the fact that the first version places the ships in the same place every time so I have started with one ship (made of two squares). I have done this by creating two functions: the first generates a random coordinate...

 # Destroyer (2 squares)
def Deploy_Destroyer_1(Player):
    rand_col_1 = randint(0,11)
    if rand_col_1 <= 5:
        rand_row_1 = randint(0,11)
    else:
        rand_row_1 = randint(6,11)
    return rand_col_1
    return rand_row_1
    if Player[rand_row_1][rand_col_1] == 'X':
        Deploy_Destroyer_1(Player)
    else:
        Deploy_Destroyer_2(Player)

and the second trials this co-ordinate against the conditions (if it will fit on the board and which rotation it can be placed).

def Deploy_Destroyer_2(Player):
    if rand_col_1 == 5 and rand_row_1 == 6:
        #can be 1, 2, 3 or 4... in that order below
        rand_position_1 = randint(1,4)
        if rand_position_1 == 1:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 + 1][rand_col_1] = 2
        if rand_position_1 == 2:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 - 1][rand_col_1] = 2
        if rand_position_1 == 3:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 + 1] = 2
        if rand_position_1 == 4:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 - 1] = 2
    elif rand_col_1 in range(1,4) and rand_row_1 in range(1,10):
        #can be any 1, 2, 3 or 4... in that order below
        rand_position_1 = randint(1,4)
        if rand_position_1 == 1:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 + 1][rand_col_1] = 2
        if rand_position_1 == 2:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 - 1][rand_col_1] = 2
        if rand_position_1 == 3:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 + 1] = 2
        if rand_position_1 == 4:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 - 1] = 2
    elif rand_col_1 in range(5,10) and rand_row_1 in range(7,10):
        #can be any 1, 2, 3 or 4... in that order below
        rand_position_1 = randint(1,4)
        if rand_position_1 == 1:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 + 1][rand_col_1] = 2
        if rand_position_1 == 2:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 - 1][rand_col_1] = 2
        if rand_position_1 == 3:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 + 1] = 2
        if rand_position_1 == 4:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 - 1] = 2
    elif rand_col_1 == 0 and rand_row_1 == 0:
        #can be any 1, 2, 3 or 4... in that order below
        rand_position_1 = randint(1,4)
        if rand_position_1 == 1:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 + 1][rand_col_1] = 2
        if rand_position_1 == 2:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 - 1][rand_col_1] = 2
        if rand_position_1 == 3:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 + 1] = 2
        if rand_position_1 == 4:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 - 1] = 2
    elif (rand_col_1 == 5 and rand_row_1 == 0) or (rand_col_1 == 11 and rand_row_1 ==6):
        #can be one or four
        #check brackets and booleans here
        rand_position_1 = randint(1,2)
        if rand_position_1 == 1: #position 1
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 + 1][rand_col_1] = 2
        if rand_position_1 == 2: #position 4
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 - 1] = 2
    elif rand_col_1 == 0 and rand_row_1 == 11:
        #can be 2 or 3
        rand_position_1 = randint(2,3)
        if rand_position_1 == 2: #position 2
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 - 1][rand_col_1] = 2
        if rand_position_1 == 3: #position 3
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 + 1] = 2
    elif rand_col_1 == 11 and rand_row_1 == 11:
        #can be 2 or 4
        rand_position_1 = randint(1,2)
        if rand_position_1 == 1: #position 2
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 - 1][rand_col_1] = 2
        if rand_position_1 == 2: #position 4
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 - 1] = 2
    elif (rand_row_1 == 0 and rand_col_1 in range(1,4)) or (rand_row_1 == 6 and rand_col_1 in range(6,10)):
        #can be 1, 3 or 4
        #check brackets and booleans here
        rand_position_1 = randint(1,3)
        if rand_position_1 == 1: #position 1
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 + 1][rand_col_1] = 2
        if rand_position_1 == 2: #position 3
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 + 1] = 2
        if rand_position_1 == 3: #position 4
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 - 1] = 2
    elif (rand_col_1 == 5 and rand_row_1 in range(1,5)) or (rand_col_1 == 11 and rand_row_1 in range(7,10)):
        #can be 1, 2 or 4
        #check brackets and booleans here
        rand_position_1 = randint(1,3)
        if rand_position_1 == 1: #position 1
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 + 1][rand_col_1] = 2
        if rand_position_1 == 2: #position 2
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 - 1][rand_col_1] = 2
        if rand_position_1 == 3: #position 4
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 - 1] = 2
    elif rand_col_1 == 0 and rand_row_1 in range(1,10):
        #can be 1, 2 or 3... in that order below
        rand_position_1 = randint(1,3)
        if rand_position_1 == 1:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 + 1][rand_col_1] = 2
        if rand_position_1 == 2:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 - 1][rand_col_1] = 2
        if rand_position_1 == 3:
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 + 1] = 2
    elif rand_col_1 in range(1,10) and rand_row_1 == 11:
        #can be 2, 3 or 4
        rand_position_1 = randint(1,3)
        if rand_position_1 == 2: #position 2
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1 - 1][rand_col_1] = 2
        if rand_position_1 == 3: #position 3
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 + 1] = 2
        if rand_position_1 == 4: #position 4
            Player[rand_row_1][rand_col_1] = 2
            Player[rand_row_1][rand_col_1 - 1] = 2

After applying my code I get this error.

    Traceback (most recent call last):
  File "<stdin>", line 310, in <module>
  File "<stdin>", line 15, in PrintBoards
TypeError: sequence item 0: expected string, NoneType found

and here is the PrintBoards function

def PrintBoards(Player,Opponent):
    print ' '*10, 'PLAYER', ' '*30, 'OPPONENT'
    letters = ['A','B','C','D','E','F','G','H','I','J','K','L']
    for x in range(6):
        print letters[x],"  ".join(map(DisplayChar,Player[x]))," "*18,"| ","  ".join(map(DisplayChar,Opponent[x]))
    for x in range(6,12):
        print letters[x],"  ".join(map(DisplayChar,Player[x]))," | ","  ".join(map(DisplayChar,Opponent[x]))
    print " ","  ".join(map(str,range(1,10)))," 10 11 12","  ","  ".join(map(str,range(1,10)))," 10 11 12"

and here is the DisplayChar function

def DisplayChar(x):
    if x==0: 
        return '?'
    elif x==1:
        return ' '
    elif x==2:
        return 'X'
    elif x==3:
        return ' '
    elif x==4:
        return '*'

I tried editing the above function to this...

def DisplayChar(x):
        if x==0: 
            return '?'
        elif x==2:
            return 'X'
        elif x==4:
            return '*'
        else:
            return ' '

However it gave me this error instead

Traceback (most recent call last):
  File "<stdin>", line 309, in <module>
  File "<stdin>", line 15, in PrintBoards
TypeError: argument 2 to map() must support iteration

I also tried printing the lists Player and Opponent after the PrintBoards function to ensure that they contain 0s and 1s (referring to the DisplayChar function) which they do (when inserted intot he original, not when I put my new and very long code in)

This next bit is in response to Michael

PLAYER                                OPPONENT
[[1, 1, 1, 1, 1, 1], [1, 2, 2, 2, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1], [1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1], [1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
[0, 0, 0, 0, 0, 0]
A                                                       |  ?  ?  ?  ?  ?  ?
<function Deploy_Destroyer_1 at 0x1c2634>
[0, 0, 0, 0, 0, 0]
B
Traceback (most recent call last):
  File "<stdin>", line 314, in <module>
  File "<stdin>", line 17, in PrintBoards
TypeError: argument 2 to map() must support iteration

EDIT

After someone kindly pointed out I had assigned the function instead of called it, I've found that another error occurred (I don't think Python likes me)

Traceback (most recent call last):
  File "<stdin>", line 313, in <module>
  File "<stdin>", line 17, in PrintBoards
TypeError: argument 2 to map() must support iteration

Below I've also included where I called the function in case I've done something silly

Player, Opponent = InitBoards()
Player = DeployFleet(Player), Deploy_Destroyer_1(Player)
PrintBoards(Player,Opponent)

EDIT 2

I changed it to what Micheal0x2a said and it ran with no errors however the ship that the code is placing disappeared :s

From what I understand, the PrintBoards function prints the board for the Player by mapping the items in the list to the DisplayChar function (if 2 is an item in the list, it prints X etc). So my novice knowledge tells me that the Deploy_Destroyer_1 function should be called in Player = in the Main function (included above) to ensure that the item in the list is changed, therefore the character printed should change.

I’m guessing that there is something wrong with my new code (Deploy_Destroyer_1) which doesn’t do this correctly (either doesn’t change the item in the list therefore doesn’t print the correct character, or something else which I can’t think of).

However there is also a big chance that I have confused myself :)

I have only been learning Python for a couple of weeks so if anyone needs more detail in order to help me please ask

回答1:

If you've arrived here because you were looking for the root cause of "TypeError: sequence item 0: expected string, NoneType found", it can come from doing something along these lines...

','.join([None])


回答2:

Your DisplayChar function does not have a default value. This would do no harm if you'd be handling all possible cases for x, but apparently you're not. Try

def DisplayChar(x):
    if x == 0: 
        return '?'
    elif x == 2:
        return 'X'
    elif x == 4:
        return '*'
    else:
        return ' '

but this will probably yield blank strings where you don't expect them.

Generally, I'd recommend going through a good Python tutorial first. All of your above code can be greatly simplified.



回答3:

The problem is most likely somewhere within these 4 lines:

for x in range(6):
    print letters[x],"  ".join(map(DisplayChar,Player[x]))," "*18,"| ","  ".join(map(DisplayChar,Opponent[x]))
for x in range(6,12):
    print letters[x],"  ".join(map(DisplayChar,Player[x]))," | ","  ".join(map(DisplayChar,Opponent[x]))

Within these lines, you've used a join statement multiple times. The join statement requires a list of strings in order to work. However, when you're mapping DisplayChar to Player[x], the DisplayChar function is returning the value None instead of a string of some sort.

If you look at the DisplayChar function, it handles values only from 0 to 4. The lists you use probably include additional numbers or characters. If x happened to be something like 5, DisplayChar will terminate and simply return the value None. Remember, functions return the value None by default.

You either need to handle these additional numbers within DisplayChar, or modify DisplayChar to contain an else statement to return an empty string, like so:

def DisplayChar(x):
    if x==0: 
        return '?'
    elif x==1:
        return ' '
    elif x==2:
        return 'X'
    elif x==3:
        return ' '
    elif x==4:
        return '*'
    else:
        return ' '

Edit:

Ok, I think I might know what's going on, given the new edits.

Notice when you were printing out Player[x], it printed <function Deploy_Destroyer_1 at 0x1c2634> the second time around?

That means somewhere, buried deep inside your code, you've done something to the effect of Player[row] = Deploy_Destroyer_1 (notice the missing parenthesis!). Instead of calling the function, you've assigned the function.

Hunting for, and adding the missing parenthesis should most likely solve the problem.

Edit 2:

I think your problem is with this line: Player = DeployFleet(Player), Deploy_Destroyer_1(Player)

If you try doing a print Player immediately after, I think you'll most likely see a large list of numbers, followed by None.

This is because the DeployFleet function is returning the table (I think?) whereas the Deploy_Destroyer_1 function returns nothing. Instead, it just mutates the Player table.

To fix this, try doing either this:

Player = DeployFleet(Player)
Deploy_Destroyer_1(Player)

...or modify Deployer_Destroyer_1 so that it returns Player when it's finished, so you can do this:

Player = DeployFleet(Player)
Deploy_Destroyer_1(Player)