Categories
Beginner education Python

Using Ridiculously Complicated Starbucks Orders to Explain Python Classes

Photo by Lisa on Pexels.com

Okay, you’re probably wondering — why Starbucks orders? Why not use normal things to explain classes? Alarm clocks? Cars? Bank accounts? Literally anything else?

Well, they say write about what you know — and I’m a millennial with a coffee addiction. So Starbucks it is, friends.

In this article, we’re going to create Python objects (*ahem* ridiculous Starbucks orders) using classes. We’ll explore classes in the context of object-oriented programming — but focus mostly on classes. (And coffee too, of course.)

Let’s go over some of the basics of object-oriented programming.

Okay, what’s object-oriented programming?

If you’re a new coder, odds are you’ve already worked mostly with procedural programming. Procedural programming works sort of like a recipe — with a series of tasks carried out in sequence using functions.

As its name suggests, object-oriented programming (OOP) carries out tasks using objects. A programming object is self-contained data type that has its own characteristics and actions. OOP allows coders to easily create and update data objects.

This is obviously a wildly over-simplified introduction to OOP. For a more complete introduction, check out Real Pythonthe w3schools website, or this awesome introduction to OOP by Tech With Tim on Youtube.

Cool. So what are classes?

Classes are object blueprints. They describe what characteristics an object has (its “attributes”) and what the object can do / have done to it (its “methods”). Classes allow users to create as many copies (or “instances”) of that object as we want. They’re especially useful for creating multiple objects of similar types — like, for instance, different Starbucks drinks.

Awesome. Now, let’s create the class we’ll use to make our objects.

Let’s create a “Drink” Class

Since I’m super creative, I’m going to go ahead and call this class “Drink”. We’ll use the following statement to create the “Drink” class:

class Drink:

Next, we’ll create an initial method (“__init__”), which takes three parameters: “self”, “size”, “name” and “type”.

class Drink:
def __init__(self, size, name, type):

Think of the “__init__” method like the “main” function. Just like most programs include a “main” function, nearly every class has an “__init__” method. By creating an object using this class, we are automatically “passing” that object as a parameter to our “__init__” method. This “self” parameter lets us create (and later customize) our objects.

Okay, but wait — weren’t we making Starbucks drinks?

Yes! Sorry. Let’s get to the fun part.

Classes have characteristics (or “attributes”). Whenever an object is created using a specific class, it automatically has the attributes defined in that class.

Cool, so — what attributes does a Starbucks drink have?

Strictly for research purposes, I ordered Starbucks and used their menu to see the different options you can select from. This is a shortened list of attributes I found from these options:

  • Name of the person ordering
  • Type of drink
  • Size
  • Flavors
  • Toppings
  • Espresso Shots
  • Sweeteners
  • Dairy

Here’s the basic format for creating an attribute in a class:

self.__[attribute] = value

One of the benefits of working with OOP is that it allows us to hide attributes — meaning that external programs cannot alter the attributes’ values. We do this by adding two underscores: “_ _” between self. and the attribute. This effectively “hides” the attribute, and prevents it from getting corrupted by external programs.

Now, let’s make these attributes part of our Drink class. (Note that these attributes can have all sorts of values — from parameters, to integers, strings, lists, and more.)

class Drink:
def __init__(self, name, size, drinkType):
self.__type = drinkType
self.__size = size
self.__name = name
self.__flavors = []
self.__numFlavors = 0
self.__toppings = []
self.__numEspresso = 0
self.__typeSweetener = "None"
self.__numSweetener = 0
self.__typeDairy = "None"

Excellent. Now, let’s move on to our methods.

Methods are basically the “verbs” of classes — they define what actions the object can perform / have performed on it.

Here’s the basic format for creating a method:

def methodName(self, parameter1, parameter2):
statement
statement
etc.

In our case, we want to create the following methods:

  • Add espresso shot → One parameter: a number. If this number is greater than 0, add it to the value of the self.__numEspresso attribute.
  • Add sweetener → Two parameters: a number and a preference (a string). If the number is greater than 0, add it to the value of the self.__numSweetener attribute. The value of the self.__typeSweetener attribute is now the preference.
  • Add flavor → Two parameters: a flavor and a number. Appends the flavor to the attribute self.__flavors (a list). Adds the number to the self.__numFlavors attribute.
  • Add topping → One parameter: topping. Appends the topping to the attribute self.__toppings (a list).
  • Add dairy → One parameter: preference. Assigns the value of “preference” to the attribute self.__typeDairy.
#Define addEspresso method
def addEspresso(self, num):
if num > 0:
self.__numEspresso += 1#Define addSweetener method
def addSweetener(self, num, preference):
if num > 0:
self.__typeSweetener = preference
self.__numSweetener += num#Define addFlavor method
def addFlavor(self, flavor, num):
self.__flavors.append(flavor)
self.__numFlavors += num#Define addTopping method
def addTopping(self, topping):
self.__toppings.append(topping)#Define addDairy method:
def addDairy(self, preference):
self.__typeDairy = preference

Final step: add a “__str__” method

This method always returns a string. We call this method by passing the object as an argument to a print statement. In our case, we’ll use this method to review our orders before we “place” them. Here’s what our code will produce:

[Name] ordered a [size] [drink type] with the following additions:[number espresso shots] Espresso shots
[number flavor shots] [flavors] Flavor shots
[dairy type]

Here’s our __str__ method:

def __str__(self):
return (f"{self.__name} ordered a {self.__size
{self.__drinkType}
with the following additions: \n"
f"{self.__numEspresso} Espresso shots \n"
f"{self.__numFlavors} {self.__flavors} flavor shots \n"
f"{self.__typeDairy}").

Now let’s make some drinks.

Drink 1. Vanessa wants a Venti double espresso vanilla latte with oat milk and three extra shots of sugar-free hazelnut.

(Three for you Vanessa. You go Vanessa.)

Our first steps: 1) import our class, and 2) create our object (Vanessa’s drink).

import drinkdrink1 = drink.Drink("Vanessa", "Venti", "Latte")

Our first statement imports the ‘Drink’ class.

Our second statement passes four arguments to the __init__ method: the name (Vanessa), the size (Venti), the drink type (Latte) and the object itself (drink1).

Now “drink1” is officially an object — it can be modified using any of the methods built into the Drink class.

Vanessa wanted two espresso shots. Let’s use the “addEspresso” method to add these to drink1.

drink1.addEspresso(2)

We’ll call the addFlavor method to add three shots of sugar-free hazelnut flavor:

drink1.addFlavor(“sugar-free hazelnut”, 3)

Let’s add our oatmilk by calling the addDairy method:

drink1.addDairy("oatmilk")

Finally, let’s review our order by calling the print method:

print(drink1)Output:
Vanessa ordered a Venti Latte with the following additions:
2 Espresso shots
3 ['hazelnut'] flavor shots
oatmilk

Drink 2. Yvette wants a Trenta Honey Almond Milk Cold Brew with a triple shot of espresso ( — Yvette, honey, are you okay? — ), four shots of vanilla flavor, and extra foam.

Here’s how we’ll do this:

#1) Create our drink object
drink2 = drink.Drink("Yvette", "Trenta", "Honey Almond Milk Cold Brew")#2) Add 3 espresso shots
drink2.addEspresso(3)#3) Add 4 vanilla flavor shots
drink2.addFlavor(“vanilla”, 4)#4) Add extra foam using the "addDairy" method
drink2.addDairy("extra foam")#5) Review the order
print(drink2)Output:
Yvette ordered a Trenta Honey Almond Milk Cold Brew with the following additions:
3 Espresso shots
4 ['vanilla'] flavor shots
extra foam

Drink 3. Matteo wants a tall Iced Starbucks Blonde Vanilla Latte with extra cream, extra foam, three pumps of Pineapple Ginger syrup, and an extra shot of espresso.

#1) Create our drink object
drink3 = drink.Drink("Matteo", "Tall", "Iced Starbucks Blonde Vanilla Latte")#2) Add 3 espresso shots
drink3.addEspresso(1)#3) Add 4 vanilla flavor shots
drink3.addFlavor(“Pineapple Ginger”, 3)#4) Add extra foam using the "addDairy" method
drink3.addDairy("extra foam, extra cream")#5) Review the order
print(drink3)Output:
Matteo ordered a Tall Iced Starbucks Blonde Vanilla Latte with the following additions:
1 Espresso shots
3 ['Pineapple Ginger'] flavor shots
extra foam, extra cream

These three objects can now be edited independent of one another. They all have the same methods and original attributes, since they were created using the same class. As always, I highly recommend playing around with the ideas discussed in this article. The best way to learn code: write code. So get started, have fun, and don’t forget to get yourself a coffee (no matter where it comes from)!

This article was originally published on Gitconnected’s Level Up Coding. You can read the original article here.

By Ayla Yersel

Humanities nerd learning to code.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s