Preliminary draft of a data structure for a goodies tracker My girlfriend and I are making a goodies tracker to enable us to keep better track of our stamp/gift cards. Right now we've got a super simple Object with some fields of what a stamp card has, and no support for modifying its fields (yet). I want to get some tips on if this is bad or good code, if there are any glaring bugs, and if possible if you'd know any good ways to look at how to integrate similar Objects like gift card and stamp card (inheritance, or composition?)

There are some dependencies which you can choose if you want to download. I'll include the output of the code here:



# -*- coding: utf-8 -*-
from tabulate import tabulate
# TODO: Put the dependencies into a venv so that it's easy to install
# TODO: add the amount of stamps we currently have vs. the stamp_capacity

class StampCard:
    # A stamp card for an establishment which contains a name and a capacity
    # Authors: Cody Antonio Gagnon &amp; Chuan-Li Ojales Chang

    def __init__(self, card_name, card_description, stamp_capacity,
                 stamp_symbol, redeemable_location):
        """
        Initialize the stamp card with a:
            name
            description
            capacity
            symbol for stamping
            location to be redeemed
        """
        self.name = card_name
        self.description = card_description
        self.stamp_capacity = stamp_capacity
        self.stamp_symbol = stamp_symbol
        self.location = redeemable_location

    def get_name(self):
        """
        Return the name of the stampcard
        """
        return self.name

    def get_description(self):
        """
        Return the description of the stampcard
        """
        return self.description

    def get_capacity(self):
        """
        Return the capacity as a string.
        """
        return str(self.stamp_capacity)

    def get_symbol(self):
        """
        Return the capacity as a string.
        """
        return self.stamp_symbol

    def get_location(self):
        """
        Return the redeemable location as a string.
        """
        return self.location

    def print_stamps(self):
        """
        Print the stamps using the typical two-row approach.
        """
        stamps = []
        stamps_per_row = self.stamp_capacity / 2  # hardcoded rows for now...
        for x in range(1, 3):
            stamps.append([self.stamp_symbol] * stamps_per_row)
        print (tabulate(stamps, tablefmt="grid").encode('utf8', 'replace'))  # takes a list of lists or another tabular data type as the first argument, and outputs a nicely formatted table


def main():
    stamp = unicode("", 'utf8')
    oasis = StampCard("Oasis", "Bubble Tea", 10, stamp, "University District")
    print("Name: " + oasis.get_name() + ", Capacity: " + oasis.get_capacity())
    oasis.print_stamps()

main()
It's weird that your get_capacity() returns a string.  I'm guessing that it's to facilitate string concatenation in the print() statement in main(), but that is not a good justification for the weirdness.  A better solution would be to use str.format() rather than string concatenation.

Those get_…() methods look like an awkward translation of Java code.  In Python, it is often customary to just access the member variables directly.  If you did want to write a getter method (to help enforce read-only access, for example), you could write a @property instead.

Going further, it seems like your StampCard is mostly a structure to hold a bunch of read-only properties.  You could just use or inherit from collections.namedtuple.

# -*- coding: utf-8 -*-
from collections import namedtuple
from tabulate import tabulate

class StampCard(namedtuple('StampCard', 'name description capacity symbol redeemable_location')):
    def __str__(self):
        stamps_per_row = self.capacity // 2  # hardcoded rows for now
        stamps = [[self.symbol] * stamps_per_row] * 2
        return tabulate(stamps, tablefmt='grid')

def main():
    oasis = StampCard('Oasis', 'Bubble Tea', 10, u'', 'University District')
    print('Name: {card.name}, Capacity: {card.capacity}'.format(card=oasis))
    print(unicode(oasis))

if __name__ == '__main__':
    main()