How to Use randit with the random module to create a six sided Dice

Hello,

I am busy with the book “Python crash course 2nd edition”. At the end of chapter 9 I get stuck so I hope anybody can help me explain why the given solution works and mine doesn’t. I added the 2 codes, correct solution and my solution. The question is to make a Die class with the randint attribute in the random module. I have to create a 6 sided Die and roll it 10 times and print the random results.

Solution:

from random import randint

class Die():
    """Represent a die, which can be rolled."""

    def __init__(self, sides=6):
        """Initialize the die."""
        self.sides = sides

    def roll_die(self):
        """Return a number between 1 and the number of sides."""
        return randint(1, self.sides)

# Make a 6-sided die, and show the results of 10 rolls.
d6 = Die()

results = []
for roll_num in range(10):
    result = d6.roll_die()
    results.append(result)
print("10 rolls of a 6-sided die:")
print(results)

My solution which doesn’t work:

from random import randint

class Die():
“”“Represent a die, which can be rolled.”""

def __init__(self, sides=6):
    """Initialize the die."""
    self.sides = sides

def roll_die(self):
    """Return a number between 1 and the number of sides."""
    return randint(1, self.sides)

Make a 6-sided die, and show the results of 10 rolls.

d6 = Die()

for roll_num in range(10):
print(roll_num)

I don’t know what I am doing wrong. What does the sulution do with “roll_num”?

Sorry for the messy post but I don’t how to do it a better way.

My solution which doesn’t work:
[…]

# Make a 6-sided die, and show the results of 10 rolls.
d6 = Die()
for roll_num in range(10):
    print(roll_num)

I don’t know what I am doing wrong. What does the sulution do with
“roll_num”?

Notice that their code actually calls d6.roll_die(). You’re does not, so
no rolling happens.

Cheers,
Cameron Simpson cs@cskk.id.au

Thanks for the answer. Ithought I had another solution worked out yesteray (I am just trying different things) but that also isn’t working. I am really confused, I really struggle with this chapter about classes. Can you or anybody tellme why my last solution also doesn’t word (sorry if it’s a stupid question)?

"""A class to roll a die of six sides."""

from random import randint

class Die():
    """Represent a die which can be rolled."""
    
    def __init__(self, sides=6):
        """
        inititialize the die.
        """
        self.sides = sides
    
    def roll_die(self):
        """Return a number from 1 to the number of sides."""
        return randint(1, self.sides)
        
        for roll_num in range(10):
            result = six.roll_die()
            print(result)
            
six = Die()
six.roll_die()

Hi Joery,

What are you confused about? It is hard for us to know what confuses you
if you don’t tell us.

Fortunately in this case I think I have the answer. You have this
“roll_die” method in your Die class:

def roll_die(self):
    """Return a number from 1 to the number of sides."""
    return randint(1, self.sides)

    for roll_num in range(10):
        result = six.roll_die()
        print(result)

Once the code reaches the return statement, the method will return and
anything beyond that will never be executed.

So when you run your code here:

six = Die()
six.roll_die()

the first line of code creates a new “Die” object, and names it “six”.
The second line then calls six’s roll_die method. So the interpreter
jumps to the method in the Die class. What happens there?

    return randint(1, self.sides)

So the method generates a random number and returns it. The for-loop
that follows doesn’t get used. It is what we call “dead code”, code that
can never be run.

My advise is, roll_die should only ever roll the die once. If I say
“roll a six sided die”, you would roll it once, not ten times. If you
want to roll it ten times, write it like this:

for i in range(10):
    result = six.roll_die()
    print(result)

I think this is just an indentation error. The for-loop was demo code in
the original programme, to roll the die several times using its
roll_die() method. I doubt it was intended to be part of the method
code.

Cheers,
Cameron Simpson cs@cskk.id.au

To my eye the code looks functional. With some issues. Let’s look at it:

class Die():
    """Represent a die which can be rolled."""

Looks fine. This introduces a Die class (with no superclasses other than
the implicit “object” superclass). Classes with no superclasses can just
be defined like this: class Die:, omitting the brackets.

I case it isn’t clear, a class does 2 primary things: each instance of
the class keeps some state (in you case, the number of sides to the die)
and provides some methods to do things with the instance from outside,
which do not need to caller to know the internals of how the class does
them. For example, roll_die() works and returns a number without the
caller knowing how the instance does that, or even how it knows how many
sides there are on the die.

    def __init__(self, sides=6):
        """
        inititialize the die.
        """
        self.sides = sides

Also fine. Sets the internal state of a new instance, by saving the
number of sides, with a default of 6.

    def roll_die(self):
        """Return a number from 1 to the number of sides."""
        return randint(1, self.sides)
        for roll_num in range(10):
            result = six.roll_die()
            print(result)

This is also fine, up to the return. it computes a (pseudo)random number
using randint() and returns that number.

However, this method also contains a for-loop which looks like it
leaked in from the other code. That loop would have tried to call the
method again. In practice: (a) the loop never runs, because of the
“return” statement above it and (b) it would fail “six”, if defined by
the time this method is called, would just call itself forever (because
six.roll_die() would call six.roll() die, which would call
six.roll_die(), which…).

The blank line you had between the “return” statement and the for-loop
does not end the method. The indentation says that the for-loop is part
of the method.

six = Die()
six.roll_die()

This is also fine. It creates a new instance of “Die” and associates it
with the variable “six”. The you call the instance’s roll_die() method,
which computes a new random value. However, you do not store that value
anywhere or print it, so you do not see the effect of calling the
method. The method is called, but the method is silent (can you imagine
the noise if every method printed stuff out?)

By changing the last line to:

print("roll =", six.roll_die())

you will see the value returned. You could equally store the value:

roll1 = six.roll_die()

or call it sevaral times and store (or print, or whatever) all the
values.

If you do not know if the method is getting called (a not uncommon
debugging situation) you can stick a print() in the method itself:

    def roll_die(self):
        """Return a number from 1 to the number of sides."""
        roll = randint(1, self.sides)
        print(f"{self}.roll_die =>", roll)
        return roll

Notice that we store the value in a variabe (a variable local to the
method - it does not leak to the caller of the method). This is because
we want to do 2 things: print it and return it. So we compute “roll”.
Then print. Then return.

Cheers,
Cameron Simpson cs@cskk.id.au

Hello Steven,

Thank you for the answer. I think I get it now. The classes cahpter in generally is what me confuses, I think I just have to practice this a lot. As you can see, I do not always choose the right place to get my code working. I will just stay practicing, I really want to learn this.
Thank you very much for your help!

Thanks for your explanation. I did not know about the return command. I was not awere the other code was "dead"code due the return command. This was a very important piece to know I think haha. Thanks for the help!