【问题标题】:Python class: TypeError: 'NoneType' object is not callablePython 类:TypeError:'NoneType' 对象不可调用
【发布时间】:2021-01-24 23:05:54
【问题描述】:

我正在尝试创建 Python 版本的 Monopoly。我有一个单独的班级,我用它来洗牌和跟踪机会卡和公益金卡。卡片存储在chest_cardschance_cards 列表中。

def __init__(self):
    self.chance = random.shuffle(chance_cards)
    self.chest = random.shuffle(chest_cards)
    self.chance_count = 0
    self.chest_count = 0
    
def chance(self):
    self.chance_count += 1
    return self.chance[self.chance_count - 1]

在我的主代码中,我只是在运行

p = cards()
print (p.chance())

测试我的代码,但打印行得到TypeError: 'NoneType' object is not callable

有什么想法吗?还是您需要查看更多代码? TIA

编辑:这是完整的 cards 课程,如果有帮助的话

import random
global chance_count
global chest_count

class cards:
    global chest_cards
    global chance_cards
    chest_cards = (["Go to Jail","Get Out of Jail Free","Advance to Go (Collect $200)",
"Bank error in your favor (Collect $200)","Doctor's fee (Pay $50)", 
"From sale of stock you get $50", "Grand Opera Night — Collect $50 from every player", 
"Holiday Fund matures (Collect $100)", "Income tax refund (Collect $20)",
"It is your birthday (Collect $10)","Life insurance matures (Collect $100)",
"Pay hospital fees of $100", "Pay school fees of $150", "Receive $25 consultancy fee",
"You are assessed for street repairs – $40 per house – $115 per hotel",
"You have won second prize in a beauty contest (Collect $10)", "You inherit $100"])

    chance_cards = (["Go to Jail","Get Out of Jail Free","Advance to Go (Collect $200)",
"Advance to Illinois Ave — If you pass Go, collect $200",
"Advance to St. Charles Place – If you pass Go, collect $200",
"Advance token to nearest Utility. If unowned, you may buy it from the Bank. If owned, throw dice and pay owner a total ten times the amount thrown.",
"Advance token to the nearest Railroad and pay owner twice the rental to which he/she is otherwise entitled. If Railroad is unowned, you may buy it from the Bank.",
"Bank pays you dividend of $50", "Go Back 3 Spaces",
"Make general repairs on all your property – For each house pay $25  –For each hotel $100",
"Pay poor tax of $15","Take a trip to Reading Railroad – If you pass Go, collect $200",
"Take a walk on the Boardwalk – Advance token to Boardwalk", 
"You have been elected Chairman of the Board – Pay each player $50",
"Your building and loan matures — Collect $150", "You have won a crossword competition (Collect $100)"])

    def __init__(self):
        self.chance = random.shuffle(chance_cards)
        self.chest = random.shuffle(chest_cards)
        self.chance_count = 0
        self.chest_count = 0
        
    def chance(self):
        self.chance_count += 1
        return self.chance[self.chance_count - 1]

【问题讨论】:

  • cards 是什么?
  • 您不能用相同的名称调用属性和方法 - random.shuffle 也会原地更改列表并且不返回任何内容。所以在你的 init 中设置 self.chance = None

标签: python python-3.x


【解决方案1】:

当你创建你的类的一个实例时(假设它在你的__init__ 函数之前是class cards:),你用一个名为chance 的方法创建了一个对象,但是在__init__ 期间你用一个属性覆盖了这个方法调用chance,返回值为random.shuffle,它始终为None,因为随机播放会就地“随机播放”列表,而不是创建一个随机顺序的新列表:

>>> chance_cards = ['card1', 'card2', 'card3']
>>> chance = random.shuffle(chance_cards)
>>> print(chance)
None

编辑:关于全局变量的说明

摆脱global的选项(你真的应该自己做一些outsidelearningvariablescope...):

  1. 将类外的变量移至“模块范围”。您仍然可以在课堂上参考它们。
import random, copy #copy isn't strictly needed but used for clarity
# `new_list=some_list[:]` is functionally equivalent to `new_list=copy.copy(some_list)`
chest_cards = (["Go to..."])
chance_cards = (["Go to Ja..."])

class cards:
    def __init__(self):
        self.chest_cards = copy.copy(chest_cards) #make a local copy so you don't alter the master list
        random.shuffle(self.chest_cards)
  1. 如果您只需要在类中使用它们,请将它们保留为类属性,并使用 self 或类名称引用它们。
import random, copy
class cards:
    chest_cards = (["Go to..."])
    chance_cards = (["Go to Ja..."])
    def __init__(self):
        #before you over-write self.chest_cards, it refers to the class attribute
        self.chest_cards = copy.copy(self.chest_cards) #make a local copy so you don't alter the master list
        #after you over-write it, it will refer to the instance attribute as long as you made a copy.
        #you can also refer to the class directly to access class-attributes
        self.chest_cards = copy.copy(cards.chest_cards)
        #if you want to get the class without calling it by name (in case you want to change the name of the class)
        self.chest_cards = copy.copy(type(self).chest_cards)
        random.shuffle(self.chest_cards)
  1. 肯定还有更多方法...看看你能不能找到任何方法:)

【讨论】:

  • 您的编辑带来了一些与全局变量范围有关的其他内容...等一下...
  • 永远不要使用全局变量——你的代码不需要它。
  • random.shuffle 不会从列表中返回随机值。它将给定的列表打乱并返回 None。
  • @TonySuffolk66 我有这个坏习惯,在我去检查我的工作是否 100% 正确之前从记忆中写下答案......我想我至少第一次接近了 ;) 感谢您的更正
  • 我也是这样做的——不用担心。
【解决方案2】:

首先:

你有一个叫做机会的数据属性和一个叫做机会的方法;因此,当您在 init 方法中设置 self.chance 时,它​​会覆盖对同名方法的引用 - 为您的 chance 属性提供不同的名称`

其次:

random.shuffle() 是一个就地函数——它会改变你传递给它的列表,并返回 NONE——这就是为什么你的机会属性设置为 None。如果你希望你的机会属性是你的机会全局的一个版本,它被洗牌 - 然后这样做:

def __init__(self):
     self.chance = chance[:]
     random.shuffle(self.chance)

def __init__(self):
     self.chance = list(random.choices(chance, k=len(chance))

第三:

全局变量——为什么(养成使用它们的习惯非常糟糕)——如果你要使用它们(为什么)不要从类体中设置——这完全没有必要,而且令人困惑。

【讨论】:

  • 我是一个非常新手的编码器,所以我会很感激任何关于替代路径的提示!我使用了全局变量,否则会出现名称错误。如何在一个类中创建在整个类中使用的变量?
  • 只需将它们包含在 class 定义内的类中,但不包含在任何方法中 - : docs.python.org/3/tutorial/… 当您需要在代码中使用它们时,请使用 class.chance_cardsclass.chest_cards跨度>
猜你喜欢
  • 2016-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-22
  • 2012-04-28
  • 2021-08-18
相关资源
最近更新 更多