【问题标题】:How to deal with NoneType error in Python?如何处理 Python 中的 NoneType 错误?
【发布时间】:2020-07-03 20:13:59
【问题描述】:

我在过去一周只学习了编码和 Python,所以这个问题似乎很明显。

我正在尝试创建一个纸牌游戏。我已经创建了我的卡片组,现在我正在尝试创建一个函数来从卡片组中移除一张卡片并测试我正在打印出卡片组。

但是,当我从牌组中随机取出一张牌,然后尝试打印牌组中剩余牌的属性时,我收到错误消息。 我创建了一个名为 Card 的类,其属性为 name、value、suit 我取出了部分很长且不完全相关的代码。 我有一个名为 the_deck 的所有卡片列表 我试图用

来解释错误

"如果 the_deck[i] 为无:继续:"

但这似乎不起作用。 这是我的代码,然后是错误。

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() 

我得到的错误是

TypeError: 'NoneType' 对象不可下标

这个错误来自于从牌组中取出一张牌。该函数的其余部分没有错误。

我该如何解决这个问题? 谢谢。

【问题讨论】:

  • remove 是就地操作。不要将结果分配回the_deck,因为它返回None
  • 这个错误意味着the_deckNone,而不是the_deck[i]是None。
  • @alaniwi 那么我应该如何正确地从 the_deck 中永久移除一张卡片?
  • 仅使用the_deck.remove(a)。因此,删除the_deck =
  • @Ronald 那会永久改变the_deck吗?我早些时候尝试过这样做,但它似乎并没有永久改变它。也许我错了。

标签: python nonetype


【解决方案1】:

我不确定您的数据是什么样的,但这是一个如何从可能有帮助的列表中删除随机数的示例。

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)

您的示例中需要注意的一点是,@alaniwi 指出,不应重新分配 the_deck = the_deck.remove(a),而应改为 the_deck.remove(a)。此外,您没有处理每次移除卡时len(the_deck) 减 1 的事实。

【讨论】:

  • 他不应该担心剩余的卡片数量。通过将whilefor 切换,他可以遍历牌组中剩下的任何内容。
【解决方案2】:

remove 列表方法通过修改列表删除传递给的元素。也就是说,它只是修改了列表名称所引用的列表。但是它返回None。如果函数/方法中没有return 语句,Python 解释器返回None

要检查 remove 方法是否返回 None,请在 Python 解释器中运行以下代码:

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

if 块将被执行。

您还可以检查如果您尝试索引和intNone 对象,Python 将返回什么类型的错误。

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

【讨论】:

  • 他永远不需要检查删除方法。他从他要移除的同一套牌中移除了一张他刚从同一套牌中得到的牌。
  • 我同意这一点。我试图给他提示如何探索 python 后台发生的事情。即使执行成功,函数也会返回 None 对象的想法对于 Python 初学者来说并不容易掌握。
  • 我明白,但我认为更好的帮助是将用户指向实际答案的方向。可以附加关于内联方法及其行为的旁白。虽然您的插图没有错,但也不是很清楚。我可以举一个更好的例子,并将其附加到我上面的答案中。
【解决方案3】:

每个问题的解决方案:

  1. remove() 视为操作,而不是解析器
  2. 使用 fstrings 连接字符串数据
  3. 将游戏逻辑与诊断分开
  4. 命名事物是什么
  5. 使用 for 循环来迭代牌组,这样您就不必担心有多少张牌了

以下脚本是如何实现解决方案列表的示例

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♣,     

一边

大多数容器类型都有直接作用于容器的内联方法。这些方法可能不会返回任何东西。您可以将此视为您告诉容器对自身执行的操作。了解内联方法是否会返回需要经验或快速浏览一些文档。例如,考虑remove()append()insert()pop()。所有这些都是内联方法,但只有pop()返回数据。

【讨论】:

    猜你喜欢
    • 2019-06-05
    • 2018-10-03
    • 1970-01-01
    • 1970-01-01
    • 2016-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多