How to deal with NoneType error in Python?

Question:

I have only picked up coding and Python in the past week so this question may seem obvious.

I am trying to create a card game. I have already created my deck of cards and now I’m trying to make a function to remove a card from the deck and to test that I am printing out the deck of cards.

However, when I remove a random card from the deck and then try to print out the properties of the remaining cards in the deck I receive an error.
I created a class called Card with attributes name, value, suit
I took out parts of the code which were very long and not exactly relevant.
I have a list of all my cards called the_deck
I tried to account for the error with

"if the_deck[i] is None:continue:"

but that doesn’t seem to work.
Here is my code and then the error.

def pick_a_card():
    a = random.choice(the_deck)
    print(a.name + " of " + a.suit)
    the_deck = the_deck.remove(a)
    i = 0
    while i <= 51:
        if the_deck[i] is None:
            continue
        else:
            print(the_deck[i].name + " of " + the_deck[i].suit)
        i+=1
pick_a_card() 

The error I get is

TypeError: ‘NoneType’ object is not subscriptable

This error comes from removing a card from the deck. The rest of the function has no errors.

How do I fix this?
Thanks.

Asked By: Martin Chapman

||

Answers:

Solutions to every issue:

  1. treat remove() as an action, not a parser
  2. use fstrings to concat string data
  3. separate game logic from diagnostics
  4. name things what they are
  5. use a for loop to iterate the deck so you never have to worry about how many cards there are

The below script is an example of how to implement the solution list

from collections import namedtuple
import random

#a simple deck generator so this example is complete
Card = namedtuple('Card', 'face suit')

def deck_generator():
    faces = [*list(map(str, range(2,11))), 'J', 'Q', 'K', 'A']
    suits = ['♠', '♥', '♦', '♣']
    deck  = []

    for s in suits:
        for f in faces:
            deck.append(Card(f, s))
            
    return deck
    
Deck = deck_generator()
#end deck generator

the_deck = Deck[:] #unique copy so you don't have to keep making the deck

#game logic
def pick_a_card():
    card = random.choice(the_deck)
    the_deck.remove(card) #action not parser
    return card #not 'a'

#diagnostic separated from game logic       
def viewdeck():
    deck = ''
    for card in the_deck: #number of remaining cards is irrelevant
        deck = f'{deck}{card.face}{card.suit}, ' #fstring
    print(deck)
    
        
card = pick_a_card() 
print(f'{card.face}{card.suit}') #fstring
#5♣

viewdeck()  
#2♠, 3♠, 4♠, 5♠, 6♠, 7♠, 8♠, 9♠, 10♠, J♠, Q♠, K♠, A♠, 
#2♥, 3♥, 4♥, 5♥, 6♥, 7♥, 8♥, 9♥, 10♥, J♥, Q♥, K♥, A♥, 
#2♦, 3♦, 4♦, 5♦, 6♦, 7♦, 8♦, 9♦, 10♦, J♦, Q♦, K♦, A♦, 
#2♣, 3♣, 4♣, 6♣, 7♣, 8♣, 9♣, 10♣, J♣, Q♣, K♣, A♣,     

Aside

Most container types have inline methods that work on the container directly. These methods may not return anything. You could perceive this as an action you are telling the container to perform on itself. Knowing if an inline method will or will not have a return comes with experience or a quick trip through some docs. As an example, consider remove(), append() or insert() versus pop(). All of these are inline methods, but only pop() returns data.

Answered By: OneMadGypsy

I am not sure what your data looks like but this is an example of how to remove a random from a list that may help.

the_deck = [*range(1, 53, 1)]

def remove_val(the_deck):
    a = random.choice(the_deck)
    the_deck.remove(a)
    print('Value removed:', a)
    print('New deck:', the_deck)

A point of note in your example is that, that @alaniwi pointed out, is that should not re-assign the_deck = the_deck.remove(a) rather it should read the_deck.remove(a). Also, you are not handling the fact that len(the_deck) reduces by 1 every time you remove a card.

Answered By: Alexander Caskie

The remove list method removes the element passed to by modifying the list. That is, it just modifies the list referenced by the list name. However it returns None. If there is no return statement in function/method, Python interpreter returns None.

To check that remove method returns None, run the following code at Python interpreter:

>>> a = [1, 2 ,3]
>>> if a.remove(1) == None:
...     print('Returns None')
...

the if block will be executed.

You can also check what type of error Python will return if you try to index and int or None object.

>>> a = None
>>> a[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not subscriptable
Answered By: samirko

How do I deal with this error: KeyError: "None of [Index([‘Primary Type’], dtype=’object’)] are in the [columns]"

Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.