【问题标题】:Python dice class that returns individual rolls返回单个掷骰的 Python 骰子类
【发布时间】:2018-06-30 10:57:43
【问题描述】:

我正在尝试创建一个带有 DiceShaker() 子类的 Die() 类。 DiceShaker() 子类应该获取 Die() 类的多个副本,滚动它们,然后返回各个滚动。这是我的 Die() 代码。

class Die(object):
 'a class representing a Die'
  def __init__(self, sides=6):
     'initialize a die, default 6 sides'
      self.sides = sides

 def roll(self):
     'roll the dice'
      self.dieRoll = random.randint(1, self.sides)


 def get(self):
     'get the current value of the die'
      return self.dieRoll

这是我的 DiceShaker() 代码。

class DiceShaker(Die):
'DiceShaker class'

def __init__(self,dieCount=1, dieSides=6, dieList = [], dieList2 = []):
    'initialize a dice shaker'
    Die.__init__(self,sides = 6) 
    self.dieCount = dieCount
    self.dieSides = dieSides
    self.dieList = dieList
    self.dieList2 = dieList2


def shake(self):
    'shake all the dice in the shaker'
    counter = 0
    dieList = [] 
    while counter != self.dieCount:
        self.dieList.append(Die.roll(self)) 
        counter = counter + 1
    return self.dieList 

def getIndividualRolls(self):
    'get a lsit of integers of all the individual die rolls'
    for items in self.dieList:
        self.dieList2.append(Die.get(self))
    return self.dieList2

getIndividualRolls() 应该返回一个包含所有通过shake() 的骰子的列表,但打印的列表总是只有一个数字。 示例:

d=DiceShaker(3)
d.shake()
[None, None, None]
d.getIndividualRolls()
[3, 3, 3]

我有 Shake() 返回 [none] 只是为了知道正确数量的骰子正在通过,但我无法弄清楚为什么 getIndividualRolls() 会不断打印出重复的骰子。谁能帮我弄清楚我做错了什么?

【问题讨论】:

  • 为什么你的DiceShaker 是Die 的子类?这是没有意义的。子类化用于is a 关系。 DiceShaker 不是Die 的类型(就像ShoppingCart 不是CartItem 的类型。你的关系是组合的。DiceShaker 有Dies(你用@987654334 反映) @)。
  • 如果您有选择,您应该学习 Python 3。Python 2 即将退出:pythonclock.org

标签: python list class return subclass


【解决方案1】:

评论太长了:

顺便说一句,您真的应该学习 Python 3。Python 2 是 on the way out。以下所有内容都适用于 Python 3。

为什么你的DiceShaker 是Die 的子类?这是没有意义的。子类化用于is a 关系。 DiceShaker 不是Die 的类型(就像ShoppingCart 不是CartItem 的类型一样)。你的关系是组合的。 DiceShaker 有 Dies(你用你的 dieList 反映)。在这种情况下,dieList 就是您所需要的。你不需要从Die继承。

您获得相同数字的根本原因是因为您继承了死亡。通过继承Die,您使DiceShaker 的行为类似于Die。这意味着您可以调用ds.roll() 和ds.get()(其中ds = DiceShaker()),它的行为与您在Die 上调用它的行为完全相同。这实际上就是您在写Dice.get(self) 时所做的事情。这相当于self.get()(因为DiceShaker 扩展了Dice)。但是DiceShaker 只是一个Die,而不是多个。所以调用get() 总是会返回同样的东西。您有效地完成了以下工作:

die = Die()
die.roll()

for other_die in self.dieList:
    self.dieList2.append(die.get())  # note you're getting the same die each time

因此,要解决此问题,您无需从 Die 继承。事实上你不应该。而是编写DieShaker 和Die。这意味着DieShaker 应该委托给它包含的Dies(通过在它们上调用get,不是它自己)。

from random import randint

class Die:
    def __init__(self, sides=6):
        self.sides = sides

    def roll(self):
        self._rolled_value = randint(1, self.sides)

    def get_value_rolled(self):
        return self._rolled_value


class DieShaker:
    def __init__(self, num_die=1, num_die_sides=6):
        self.dice = [Die(num_die_sides) for _ in range(num_die)]

    def shake(self):
        for die in self.dice:
            die.roll()

    def get_values_rolled(self):
        return [die.get_value_rolled() for die in self.dice]

注意在get_values_rolled(相当于您的DieShaker.getIndividualRolls)中,我们如何在我们的摇床包含的每个Die(在列表self.dice)上调用get_value_rolled(相当于您的Die.get)。

另请注意,我通过以下方式清理了您的代码:

  • 在 Python 中,对变量/属性和函数使用 snake_case 是一种惯例
  • 我重命名了一些函数以使它们之间的关系更加清晰(get_value_rolled 和 get_values_rolled)
  • 我使用了list comprehensions(例如[Die(num_die_sides) for _ in range(num_die)] 与appends 到self.dieList 的while 循环相同,但更符合pythonic)
  • 我将while 替换为for。通常在 python 中,当您使用可迭代对象时,您希望使用for(列表list)。
  • 我删除了DieShaker 构造函数的一些可选参数。出于您的目的,允许它们被传入没有多大意义(如果您想涉足更技术性的领域,那么您这样做是有原因的,但出于您现在的目的,不要这样做) .看起来您可能认为您需要将所有内容都作为__init__ 的参数,但事实并非如此。而不是这个(实际上是has a serious issue unrelated to the style/semantics):

不好:

def __init__(self, num_die=1, die_sides=6, dice = []):
    self.dice = dice

你可能应该这样做:

def __init__(self, num_die=1, die_sides=6):
    self.dice = []
  • 我删除了您的第二个列表。您只需要维护一个 die 列表(因为在每个 die 上调用 roll() 后,它每次都会为 get_value() 返回相同的内容)

【讨论】:

    【解决方案2】:

    您的DieShaker 类应该只是Die 对象列表的包装器。

    class Die(object):
        'a class representing a Die'
        def __init__(self, sides=6):
            'initialize a die, default 6 sides'
            self.sides = sides
            # You should make sure that by the time someone has created a Die object, 
            # all the attributes they might want to access have been defined
            self.roll()
    
       def roll(self):
           'roll the dice'
            self.dieRoll = random.randint(1, self.sides)
    
       # Note I got rid of Die.get 
       # Anyone who can call Die.get can see Die.dieRoll
    
    class DiceShaker(object):
        def __init__(self, dice=()): # Note we avoid mutable default arguments
            self.dice = list(dice)   # Presumably it would be nice to add/remove dice
    
        def shake(self):
            for die in self.dice:
                die.roll()
            # return self.get_dice() 
            # It doesn't really make sense for this to return anything
    
        def get_dice(self):
            return [die.dieRoll for die in self.dice]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-29
      • 2021-10-07
      相关资源
      最近更新 更多