Basic python dice simulator with log function I had created a dice simulator using nothing but functions, but I wanted to attempt one using a class for the dice just to help get a better understanding of classes.  I'm still a little in the dark on OOP and I feel like it was poorly implemented here, but I achieved what I was going for and I feel like that's at least something.  Any tips on improvement would be appreciated.

#!/usr/bin/env python
import time
from sys import exit
from random import randint

class Die(object):
    """
    Creates a die class for use with a dice rolling utility

    """
    d_sides = None
    def __init__(self, sides = 6):
        self._sides = sides
        self._value = None
        self.roll()


    def roll(self):
        """
        Generate a random integer based off the number of sides
        """
        self._value = randint(1, self._sides)
        return self._value

    def __str__(self):
        """
        Return string containing dice sides and result
        """
        return "Die with {} sides.  Result : {}".format(self._sides, self._value)

def banner():
    """
    Print out in console upon running script
    """
    print "-" * 10
    print "Snake Eyes"
    print "-" * 10

def dice_cup():
    """
    Takes user input for number of sides and number of dice then creates
    dice objects respectively
    """
    global d_sides

    # Asks for a number of dice and verifies that it's a number
    while True:
        try:
            number = int(raw_input("How many dice?\n&gt;"))
            break
        except(TypeError, ValueError):
            print "Please enter a number\n"

    # Asks for a number of sides and verifies that it's a number
    while True:
        try:
            sides = int(raw_input("How many sides?\n&gt;"))
            d_sides = sides
            break
        except (TypeError, ValueError):
            print "Please enter a number\n"
    # Generates dice objects

    dice_roll = [Die(sides).roll() for _ in range(int(number))]
    return dice_roll


def print_dice(d):
    """
    Converts list of dice results into string and prints results and total
    """

    # Converts list of dice results into a string
    dice_str = ','.join(map(str, d))
    # Adds total from dice roll
    total = sum(d)
    print "You rolled: {}\nTotal: {}".format(dice_str, total)


def dice_log(sides, number, roll):
    dash = '-' * 4
    f = open("dice_log.txt","a")
    f.write('\n')
    f.write(time.strftime('%I:%M:%S'))
    f.write('\n')
    f.write(dash)
    f.write('\n{}d{}\n'.format(number, sides))
    f.write(dash)
    f.write('\n{}\n'.format(','.join(map(str, roll))))
    f.write(dash)
    f.write('\nTotal\n')
    f.write(dash)
    f.write('\n{}\n'.format(sum(roll)))
    f.close



def engine():
    global d_sides
    banner()
    raw_input("Press enter to begin.")
    while True:
        roll = dice_cup()
        print_dice(roll)
        dice_log(d_sides, len(roll) , roll)
        cont = raw_input("Return to roll again or quit to exit\n&gt;")
        if cont.lower() == "quit":
            print "\nGoodbye."
            exit(0)

def main():
    engine()


if __name__ == "__main__":
    main()
There's some things I really like about your code. For one, you used str.format, which is in many ways superior to '%'-formatting. You also included docstrings, which help others better understand your code.

The other answers already covered most major problems. I'll be answering mostly in terms of design choice.

Object oriented programming (and why it doesn't apply here)

Classes should be thought of as containers that capture 'state'. Methods can act on that state and properties can be used to query it. A die, however, doesn't have any sense of state. A good rule of thumb is that if a class has only two methods, one of which is the constructor, then it shouldn't be a class.

I'd go further and say that you shouldn't consider creating a class if you are not confident that there is a sense of state in your program that could be grouped together. If you want to know more, there's this well known talk on when not to use classes.

Python 3!

Python 3 rocks, and you should definitely start using it right now. Python 2 only has so much time left, and switching to Python 3 isn't that hard. The only changes that affect this code:


Python 3 got rid of raw_input and replaced it with input.
print is now a function, not a statement.


If you absolutely, positively feel like you need to maintain backwards compatibility with Python 2:

try:
    input = raw_input
except NameError:
    # Python 3; `raw_input` is not defined
    pass