{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Object-oriented programming (OOP) \n", "One of the most popular programming paradigms is OOP. Number of programming languages support OOP,
\n", "e.g., Java, SmallTalk, C++,..etc. In this lecture, we show how we can use Python to carry out some OOP.
\n", "\n", "**Created and updated by** John C. S. Lui on October 12, 2020.\n", "\n", "**Important note:** *If you want to use and modify this notebook file, please acknowledge the author.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Concept of Classes\n", "\n", "One important concept in OOP is the use of classes. Class is a way to combine data and behavior of data\n", "within a construct. For example, let's consider what you'd need to do if you were creating\n", "a rocket ship in a physics simulation. One of the first things you'd want to track are the\n", "x and y coordinates of the rocket. Here is what a simple rocket ship class looks like in code:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Rocket is a class which simulates a rocket ship\n", "class Rocket():\n", " \n", " def __init__(self): # Each rocket has an (x,y) position, and these are the *data* of this class\n", " self.x = 0\n", " self.y = 0\n", "\n", " def move_up(self): # a method which moves the rocket ship up by 1 unit in the y-coordinate\n", " self.y = self.y + 1\n", " \n", "\n", "# One can *instantiate* an instance of the Rocket class\n", "my_rocket = Rocket() # instantiate an instance\n", "\n", "# my_rocket has a copy of each of the class's variables, \n", "# and it can do any action that is defined for the class.\n", "\n", "print(my_rocket) # shows that my_rocket is stored at a particular location in memory\n", "print('my_rocket x value is = ', my_rocket.x, \", my rocket y value is = \", my_rocket.y, \"\\n\") # access instance's data\n", "\n", "# Let's instantiate another rocket\n", "Johnny_rocket = Rocket()\n", "Johnny_rocket.move_up()\n", "print(Johnny_rocket)\n", "print(\"Johnny Rocket x value is = \", Johnny_rocket.x, \"Johnny Rocket y value is = \", Johnny_rocket.y)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Let's see how we can invoke the class's method\n", "\n", "# Rocket is a class which simulates a rocket ship\n", "class Rocket():\n", " \n", " def __init__(self): # Each rocket has an (x,y) position, and these are the *data* of this class\n", " self.x = 0\n", " self.y = 0\n", "\n", " def move_up(self): # a method which moves the rocket ship up by 1 unit in the y-coordinate\n", " self.y = self.y + 1\n", " \n", "\n", "# One can *instantiate* an instance of the Rocket class\n", "my_rocket = Rocket() # instantiate an instance\n", "\n", "for counter in range(3):\n", " my_rocket.move_up() # invoke class function\n", "\n", "print('my_rocket x value is = ', my_rocket.x, \", my rocket y value is = \", my_rocket.y)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The following code shows that one can create **multiple instances** of the Rocket class\n", "\n", "class Rocket(): \n", " def __init__(self): # Each rocket has an (x,y) position.\n", " self.x = 0\n", " self.y = 0\n", " \n", " def move_up(self): # Increment the y-position of the rocket.\n", " self.y += 1\n", " \n", "# Create a fleet of 5 rockets, and store them in a list.\n", "my_rockets = []\n", "for x in range(0,5): # go through the loop 5 times\n", " new_rocket = Rocket()\n", " my_rockets.append(new_rocket) # my_rocket contains 5 Rocket class instances\n", "\n", "# Show that each rocket is a separate object.\n", "for rocket in my_rockets:\n", " print(rocket)\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The following code shows a more elegant way to create **multiple instances** of the Rocket class \n", "# using **list comprehension**\n", "\n", "class Rocket(): \n", " def __init__(self): # Each rocket has an (x,y) position.\n", " self.x = 0\n", " self.y = 0\n", " \n", " def move_up(self): # Increment the y-position of the rocket.\n", " self.y += 1\n", " \n", "# Create a fleet of 5 rockets, and store them in a list.\n", "my_rockets = [Rocket() for x in range(0,5)] # This is a more elegant way to create via list comprehension\n", "\n", "# Show that each rocket is a separate object.\n", "for rocket in my_rockets:\n", " print(rocket)\n", "\n", "my_rockets[0].move_up()\n", "my_rockets[1].move_up()\n", "my_rockets[1].move_up()\n", "my_rockets[3].move_up()\n", "my_rockets[3].move_up()\n", "my_rockets[3].move_up()\n", "my_rockets[4].move_up()\n", "my_rockets[4].move_up()\n", "\n", "for rocket in my_rockets: # Let's display their y-values\n", " print('For rocket in memory:', rocket, ', its altitude is: ', rocket.y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## OOP\n", "Classes are the core component of OOP. When you want to use a class in one of your programs,
\n", "you make an object (or instance) from that class, which is where the phrase \"object-oriented\" comes from.
\n", "Python itself is not tied to OOP, but can also be used as a functional programming language (see this later).
\n", "Let's introduce some *terminologies* for OOP\n", "* **attribute** is a piece of information or data within a class. E.g., x and y in Rocket().\n", "* **behavior** is an action that defined within a class. E.g., mov_up() in Rocket().\n", "* **object** is a particular instance of a class. E.g., my_rocket\n", "\n", "Let's us try to refine our Rocket class." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Accepting parameters for the __init__() method\n", "We can generalize the __init__() method by adding a couple keyword arguments so that new rockets
\n", "can be initialized at any position." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Rocket():\n", " \n", " def __init__(self, x=0, y=0): # using keywords with default values\n", " self.x = x\n", " self.y = y\n", " \n", " def move_up(self): # Increment the y-position of the rocket.\n", " self.y += 1\n", " \n", "# Make a series of rockets at different starting places.\n", "rockets = []\n", "rockets.append(Rocket())\n", "rockets.append(Rocket(0,10))\n", "rockets.append(Rocket(100,0))\n", "\n", "# Show where each rocket is.\n", "for index, rocket in enumerate(rockets): # let's look up the documentation of enumerate() function\n", " print(\"Rocket %d is at (%d, %d).\" % (index, rocket.x, rocket.y))\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Accepting parameters in a method\n", "Let's now generalize it to any method." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Rocket():\n", " \n", " def __init__(self, x=0, y=0):\n", " # Each rocket has an (x,y) position.\n", " self.x = x\n", " self.y = y\n", "\n", "# a new method move_rocket() which we can move in x and y coordinates\n", " def move_rocket(self, x_increment=0, y_increment=1): # note that parameters are initialized \n", " self.x += x_increment\n", " self.y += y_increment\n", " \n", "# Create three rockets.\n", "rockets = [Rocket() for x in range(0,3)] # use list comprehension\n", "\n", "# Move each rocket a different amount.\n", "rockets[0].move_rocket()\n", "rockets[1].move_rocket(10,10)\n", "rockets[2].move_rocket(-10,0)\n", " \n", "# Show where each rocket is.\n", "for index, rocket in enumerate(rockets):\n", " print(\"Rocket %d is at (%d, %d).\" % (index, rocket.x, rocket.y))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Adding a new method\n", "Let's try to add a new method so that we can compute the Euclidean distance between two rockets." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# We need the math library so that we can use various functions, e.g., sqrt()\n", "from math import sqrt\n", "\n", "class Rocket():\n", " \n", " def __init__(self, x=0, y=0):\n", " self.x = x\n", " self.y = y\n", " \n", " def move_rocket(self, x_increment=0, y_increment=1):\n", " self.x += x_increment\n", " self.y += y_increment\n", " \n", " def get_distance(self, other_rocket):\n", " # Calculates the distance from this rocket to another rocket,\n", " # and returns that value.\n", " distance = sqrt((self.x-other_rocket.x)**2+(self.y-other_rocket.y)**2)\n", " return distance\n", " \n", "# Make two rockets, at different places.\n", "rocket_0 = Rocket()\n", "rocket_1 = Rocket(10,5)\n", "\n", "# Show the distance between them.\n", "distance = rocket_0.get_distance(rocket_0)\n", "print(\"The rockets are %f units apart.\" % distance)\n", "distance = rocket_0.get_distance(rocket_1)\n", "print(\"The rockets are %f units apart.\" % distance)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Concept of Inheritance in OOP\n", "\n", "One of the most important goals of the OOP is the creation of stable, reliable, reusable code.
\n", "If you had to create a new class for every kind of object you wanted to model, you would hardly have any
\n", "reusable code. In Python (which supports OOP_, one class can **inherit** from another class. This means you can
\n", "create a *new class* on an *existing class*; the new class inherits all of the attributes and behavior of the class
\n", "it is based on. A new class can **override** any undesirable attributes or behavior of the class
\n", "it inherits from, and it can add any new attributes or behavior that are appropriate.
\n", "\n", "The original class is called the **parent class**, and the new class is a **child** of the parent class.
\n", "The parent class is also called a **superclass**, and the child class is also called a **subclass**.\n", "\n", "The child class inherits *all attributes and behavior from the parent class*, but any attributes that
\n", "are defined in the child class are *not available to the parent class*. The child class can also override
\n", "behavior of the parent class. If a child class defines a method that also appears in the parent class,
\n", "objects of the child class will use the new method rather than the parent class method.\n", "\n", "Let's illustrate this concept.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from math import sqrt\n", "\n", "class Rocket():\n", " def __init__(self, x=0, y=0):\n", " self.x = x\n", " self.y = y\n", " \n", " def move_rocket(self, x_increment=0, y_increment=1):\n", " self.x += x_increment\n", " self.y += y_increment\n", " \n", " def get_distance(self, other_rocket):\n", " distance = sqrt((self.x-other_rocket.x)**2+(self.y-other_rocket.y)**2)\n", " return distance\n", " \n", "class Shuttle(Rocket): # Shuttle is a child of the Rocket() class, flights_completed states # of completion.\n", " \n", " def __init__(self, x=0, y=0, flights_completed=0): # this is the init() function for the Shuttle() class\n", " super().__init__(x, y) # it first calls its parent's __init__() method\n", " self.flights_completed = flights_completed # it also does its own initialization to its variable\n", " \n", "shuttle = Shuttle(10,0,3)\n", "print(shuttle) \n", "print(\"This shuttle has x = \", shuttle.x, \"y = \", shuttle.y, \"# of completed flights = \", shuttle.flights_completed)\n", "\n", "shuttle_2 = Shuttle(1,1,1)\n", "rocket_2 = Rocket(2,2)\n", "print('distance=', shuttle.get_distance(shuttle_2))\n", "print('distance between shuttle and rocket is: ', shuttle.get_distance(rocket_2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Let's generate some rockets and shuttles and compute their distance" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from math import sqrt\n", "from random import randint # this generates a random integer between a lower and upper bound\n", "\n", "class Rocket():\n", " \n", " def __init__(self, x=0, y=0):\n", " self.x = x\n", " self.y = y\n", " \n", " def move_rocket(self, x_increment=0, y_increment=1):\n", " self.x += x_increment\n", " self.y += y_increment\n", " \n", " def get_distance(self, other_rocket):\n", " distance = sqrt((self.x-other_rocket.x)**2+(self.y-other_rocket.y)**2)\n", " return distance\n", " \n", "class Shuttle(Rocket):\n", " \n", " def __init__(self, x=0, y=0, flights_completed=0):\n", " super().__init__(x, y)\n", " self.flights_completed = flights_completed\n", " \n", " \n", "# Create several shuttles and rockets, with random positions.\n", "# Shuttles have a random number of flights completed.\n", "shuttles = []\n", "for index in range(0,3):\n", " x = randint(0,100) # generate a random number for x\n", " y = randint(1,100) # generate a random number for y\n", " flights_completed = randint(0,10) # generate a random # for number of completed flight\n", " shuttles.append(Shuttle(x, y, flights_completed))\n", "\n", "rockets = []\n", "for index in range(0,3):\n", " x = randint(0,100)\n", " y = randint(1,100)\n", " rockets.append(Rocket(x, y))\n", " \n", "# Show the number of flights completed for each shuttle.\n", "for index, shuttle in enumerate(shuttles):\n", " print(\"Shuttle %d has completed %d flights.\" % (index, shuttle.flights_completed))\n", " \n", "print(\"\\n\") \n", "# Show the distance from the first shuttle to all other shuttles.\n", "first_shuttle = shuttles[0]\n", "for index, shuttle in enumerate(shuttles):\n", " distance = first_shuttle.get_distance(shuttle)\n", " print(\"The first shuttle is %f units away from shuttle %d.\" % (distance, index))\n", "\n", "print(\"\\n\")\n", "# Show the distance from the first shuttle to all other rockets.\n", "for index, rocket in enumerate(rockets):\n", " distance = first_shuttle.get_distance(rocket)\n", " print(\"The first shuttle is %f units away from rocket %d.\" % (distance, index))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## More examples\n", "\n", "Let's illustrate more about OOP." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class BankAccount(object):\n", " def __init__(self, balance=0):\n", " self.balance = balance\n", " def deposit (self, amount):\n", " self.balance = self.balance + amount\n", " def withdraw (self, amount):\n", " self.balance = self.balance - amount\n", " def getBalance(self):\n", " return self.balance\n", "\n", "my_account1 = BankAccount (200)\n", "# what is the balance in my_account1 ?\n", "print ('my_account 1 balance: ', my_account1.getBalance())\n", "\n", "my_account2 = BankAccount ()\n", "# what is the balance in my_account2 ?\n", "print ('my_account 2 balance: ', my_account2.getBalance())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Let's examine the class and dictionary of this class\n", "print(my_account1.__class__)\n", "print (my_account1.__dict__)\n", "print (my_account2.__dict__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Objects are referecens\n", "\n", "Objects are internally stored as references. So assigning an object only means its reference being copies. Let's illustrate." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "husband_account = BankAccount(500)\n", "\n", "print(\"hushand account has a balance of = \", husband_account.balance)\n", "\n", "\n", "wife_account = husband_account # pass by reference\n", "wife_account.withdraw(300)\n", "\n", "print(\"hushand account's balance = \", husband_account.balance)\n", "print(\"wife account's balance = \", wife_account.balance)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Let's illustrate again the concept of inheritance\n", "\n", "class BankAccount(object):\n", " def __init__(self, balance=0):\n", " self.balance = balance\n", " def deposit (self, amount):\n", " self.balance = self.balance + amount\n", " def withdraw (self, amount):\n", " self.balance = self.balance - amount\n", " def getBalance(self):\n", " return self.balance\n", "\n", "\n", "class CheckAccount(BankAccount):\n", " def __init__(self, initBal=0):\n", " BankAccount.__init__(self, initBal)\n", " self.checkRecord = {}\n", " def processCheck(self, number, toWho, amount):\n", " self.withdraw(amount)\n", " self.checkRecord[number]= (toWho, amount)\n", " def checkInfo(self, number):\n", " if number in self.checkRecord:\n", " return self.checkRecord[number]\n", "\n", "ca = CheckAccount (1000)\n", "ca.processCheck(100, 'CUHK', 328.)\n", "ca.processCheck(101, 'HK Electric', 452.)\n", "print('Check 101 has information of: ', ca.checkInfo(101))\n", "print ('The current balance is: ', ca.getBalance())\n", "ca.deposit(100)\n", "print('The current balance is: ', ca.getBalance())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## More example about OOP\n", "\n", "Let's try to build a calculator which uses reverse polish notation (RPN)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## First, let us define a stack class\n", "class Stack(object):\n", " def __init__(self):\n", " self.storage = []\n", " def push (self, newValue):\n", " self.storage.append( newValue )\n", " def top(self):\n", " return self.storage[len(self.storage) - 1]\n", " def pop(self):\n", " result = self.top()\n", " self.storage.pop()\n", " return result\n", " def isEmpty(self):\n", " return len(self.storage) == 0\n", "\n", "# let's run some program\n", "stackOne = Stack()\n", "stackTwo = Stack()\n", "stackOne.push( 12 )\n", "stackTwo.push( 'abc' )\n", "stackOne.push( 23 )\n", "\n", "print('top element for stackOne is: ', stackOne.top())\n", "\n", "stackOne.pop()\n", "print('top element for stackOne is: ', stackOne.top())\n", "print('top element for stackTwo is: ', stackTwo.top())\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Now define a calculator class\n", "class CalculatorEngine(object):\n", " def __init__(self):\n", " self.dataStack = Stack()\n", " def pushOperand (self, value):\n", " self.dataStack.push( value )\n", " def currentOperand ( self ):\n", " return self.dataStack.top()\n", " def performBinary (self, fun ):\n", " right = self.dataStack.pop()\n", " left = self.dataStack.pop()\n", " self.dataStack.push( fun(left, right))\n", " def doAddition (self):\n", " self.performBinary(lambda x, y: x + y)\n", " def doSubtraction (self):\n", " self.performBinary(lambda x, y: x - y)\n", " def doMultiplication (self):\n", " self.performBinary(lambda x, y: x * y)\n", " def doDivision (self):\n", " self.performBinary(lambda x, y: x / y)\n", " def doTextOp (self, op):\n", " if (op == '+'): self.doAddition()\n", " elif (op == '-'): self.doSubtraction()\n", " elif (op == '*'): self.doMultiplication()\n", " elif (op == '/'): self.doDivision()\n", "\n", "# Now let's test our program\n", "calc = CalculatorEngine() # instantiate a calculator\n", "calc.pushOperand( 3 ) # push operand on the stack\n", "calc.pushOperand( 4 ) # push operand on the stack\n", "calc.doTextOp ( '*' ) # do multiplication\n", "print ('The result is = ', calc.currentOperand())\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Now define an RPNCalculator\n", "class RPNCalculator(object):\n", " def __init__(self):\n", " self.calcEngine = CalculatorEngine()\n", " def eval (self, line):\n", " words = line.split(\" \")\n", " for item in words:\n", " if item in '+-*/':\n", " self.calcEngine.doTextOp( item )\n", " else:\n", " self.calcEngine.pushOperand( int (item))\n", " return self.calcEngine.currentOperand()\n", " def run(self):\n", " while True:\n", " line = input(\"type an expression: \")\n", " if len(line) == 0:\n", " break\n", " print (self.eval( line ))\n", "\n", "# Now let's instantiate an RPN calculator and do some testing\n", "calc = RPNCalculator()\n", "calc.run()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modules and classes\n", "\n", "Python allows you to **save your classes in another file** and then **import** them into the program
\n", "you are working on. This has the added advantage of isolating your classes into files that can be used in any
\n", "number of different programs. As you use your classes repeatedly, the classes become more reliable and complete overall.\n", "\n", "When you save a class into a separate file, that file is called a **module**. You can have any number of classes
\n", "in a single module. There are a number of ways you can then import the class you are interested in. Let's illustrate." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# load from rocket.py\n", "from rocket import Rocket # only import the Rocket() class \n", "\n", "rocket = Rocket()\n", "print(\"The rocket is at (%d, %d).\" % (rocket.x, rocket.y))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from rocket import Rocket, Shuttle # load both classes !!!\n", "\n", "rocket = Rocket()\n", "print(\"The rocket is at (%d, %d).\" % (rocket.x, rocket.y))\n", "\n", "shuttle = Shuttle(1,2,3)\n", "print(\"\\nThe shuttle is at (%d, %d).\" % (shuttle.x, shuttle.y))\n", "print(\"The shuttle has completed %d flights.\" % shuttle.flights_completed)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Several ways to import modules and classes\n", "\n", "The general syntax is:\n", "\n", "*from* module_name *import* ClassName\n", "\n", "Several ways to import:\n", "* import rocket
\n", " This will load all classes within the rocket module (or file)
\n", "     After this, classes are accessed using **dot notation**, or module_name.ClassName (e.g., rocket.Rocket()
\n", "* import module_name as local_module_name
\n", "\n", "Let's see an example\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Save as rocket_game.py\n", "import rocket as rocket_module\n", "\n", "rocket = rocket_module.Rocket()\n", "print(\"The rocket is at (%d, %d).\" % (rocket.x, rocket.y))\n", "\n", "shuttle = rocket_module.Shuttle()\n", "print(\"\\nThe shuttle is at (%d, %d).\" % (shuttle.x, shuttle.y))\n", "print(\"The shuttle has completed %d flights.\" % shuttle.flights_completed)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## A module of functions\n", "\n", "Let's create a file in the current directory as multiplying.py" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Save as multiplying.py\n", "def double(x):\n", " return 2*x\n", "\n", "def triple(x):\n", " return 3*x\n", "\n", "def quadruple(x):\n", " return 4*x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using the: from *module_name* import *function_name* syntax:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from multiplying import double, triple, quadruple\n", "\n", "print(double(5))\n", "print(triple(5))\n", "print(quadruple(5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using the *import module_name* syntax:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import multiplying\n", "\n", "print(multiplying.double(5))\n", "print(multiplying.triple(5))\n", "print(multiplying.quadruple(5))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using the *import* module_name *as* local_module_name syntax:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import multiplying as m\n", "\n", "\n", "print(m.double(5))\n", "print(m.triple(5))\n", "print(m.quadruple(5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using the *from* module_name import * syntax:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from multiplying import *\n", "\n", "print(double(5))\n", "print(triple(5))\n", "print(quadruple(5))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.3" } }, "nbformat": 4, "nbformat_minor": 2 }