{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Object-Oriented Programming (OOP) in Python 3\n", "\n", "In this lecture you’ll pick up the following basic concepts of OOP in Python:\n", "\n", "1. Python Classes\n", "2. Object Instances\n", "3. Defining and Working with Methods\n", "4. OOP Inheritance\n", "\n", "Most contents can be found [here](https://realpython.com/python3-object-oriented-programming/)." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## What Is Object-Oriented Programming (OOP)?\n", "\n", "**Object-oriented Programming** is a programming paradigm which provides a means of structuring programs so that properties and behaviors are bundled into individual objects.\n", "\n", "For instance, an object could represent a person with a **property** *name, age, address, etc.,* with **behaviors** like *walking, talking, breathing, and running*. Or an email with properties like recipient list, subject, body, etc., and behaviors like adding attachments and sending.\n", "\n", "As a result object-oriented programming is an approach for modeling concrete, real-world objects like cars as well as the relations between objects like companies and employees, students and teachers, etc. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Classes in Python\n", "\n", "Focusing first on the data, each thing or object is an instance of some class. The primitive data structures available in Python, like numbers, strings, and lists are designed to represent simple things like the cost of something, the name of a poem, and your favorite colors, respectively.\n", "\n", "What if you wanted to represent something much more complicated?\n", "\n", "For example, let’s say you wanted to track a number of different animals. If you used a list, the first element could be the animal’s name while the second element could represent its age." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "How would you know which element is supposed to be which? What if you had 100 different animals? Are you certain each animal has both a name and an age, and so forth? What if you wanted to add other properties to these animals? This lacks organization, and it’s the exact need for classes.\n", "\n", "`Classes` are used to create new user-defined data structures that contain arbitrary information about something. In the case of an animal, we could create an `Animal()` class to track properties about the Animal like the `name` and `age`." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "It’s important to note that a class just provides structure—it’s a blueprint for how something should be defined, but it doesn’t actually provide any real content itself. The **Animal()** class may specify that the name and age are necessary for defining an animal, but it will not actually state what a specific animal’s name or age is.\n", "\n", "It may help to think of a class as an idea for how something should be defined." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Python Objects (Instances)\n", "\n", "While the class is the blueprint, an instance is a copy of the class with **actual values**, literally an object **belonging** to a **specific class**. It’s not an idea anymore; it’s an actual animal, like a dog named Roger who’s eight years old.\n", "\n", "Put another way, a class is like a form or questionnaire. It defines the needed information. After you fill out the form, your specific copy is an instance of the class; it contains actual information relevant to you.\n", "\n", "You can fill out multiple copies to create many different instances, but without the form as a guide, you would be lost, not knowing what information is required. Thus, before you can create individual instances of an object, we must first specify what is needed by defining a class." ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "class Dog:\n", " pass" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "You start with the **class keyword** to indicate that you are creating a class, then you add the name of the class (using CamelCase notation, starting with a capital letter.)\n", "\n", "Also, we used the Python keyword `pass` here. This is very often used as a place holder where code will eventually go. It allows us to run this code without throwing an error." ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "ename": "SyntaxError", "evalue": "unexpected EOF while parsing (, line 1)", "output_type": "error", "traceback": [ "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m class Dog:\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m unexpected EOF while parsing\n" ] } ], "source": [ "class Dog:" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Instance Attributes\n", "\n", "All classes create objects, and all objects contain characteristics called **attributes** (referred to as properties in the opening paragraph). Use the __init__() method to initialize (e.g., specify) an object’s initial attributes by giving them their default value (or state). This method must have at least one argument as well as the self variable, which refers to the object itself (e.g., Dog)." ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "class Dog:\n", "\n", " # Initializer / Instance Attributes\n", " def __init__(self, name, age):\n", " self.name = name\n", " self.age = age" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "In the case of our `Dog()` class, each dog has a specific name and age, which is obviously important to know for when you start actually creating different dogs. Remember: the class is just for defining the Dog, not actually creating instances of individual dogs with specific names and ages; we’ll get to that shortly.\n", "\n", "Similarly, the `self` variable refers to the instance of the class. Since instances of a class have varying values, like different dogs, we could state Dog.name = name rather than self.name = name. But since not all dogs share the same name, we need to be able to assign different values to different instances. Hence the need for the special `self` variable, which will help to keep track of individual instances of each class.\n", "\n", "\n", "\n", "**NOTE:** You will never have to call the `__init__()` method; it gets called automatically when you create a new `Dog` instance.\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Class Attributes\n", "\n", "While instance attributes are specific to each object, class attributes are the same **for all instances**—which in this case is all dogs." ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "class Dog:\n", "\n", " # Class Attribute\n", " species = 'mammal'\n", "\n", " # Initializer / Instance Attributes\n", " def __init__(self, name, age):\n", " self.name = name\n", " self.age = age" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "So while each dog has a unique name and age, every dog will be a mammal.\n", "\n", "Let’s create some dogs…" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Instantiating Objects\n", "\n", "Instantiating is a fancy term for creating a new, unique instance of a class.\n", "\n", "For example:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "class Dog:\n", "... pass" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "<__main__.Dog at 0x7fbb117bbd50>" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dog()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "<__main__.Dog at 0x7fa230b5bd30>" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dog()" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "a=Dog()" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "b=Dog()" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a == b" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "We started by defining a new `Dog()` class, then created two new dogs, each assigned to different objects. So, to create an instance of a class, you use the the class name, followed by parentheses. Then to demonstrate that each instance is actually different, we instantiated two more dogs, assigning each to a variable, then tested if those variables are equal.\n", "\n", "What do you think the type of a class instance is?" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "a=Dog()" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "__main__.Dog" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(a)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "We can then create `instances` of this class:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "class Dog:\n", "\n", " # Class Attribute\n", " species = 'mammal'\n", "\n", " # Initializer / Instance Attributes\n", " def __init__(self, name, age):\n", " self.name = name\n", " self.age = age\n" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "# Instantiate the Dog object\n", "philo = Dog(\"Philo\", 5)\n", "mikey = Dog(\"Mikey\", 6)" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Philo is 5 and Mikey is 6.\n" ] } ], "source": [ "# Access the instance attributes\n", "print(\"{} is {} and {} is {}.\".format(\n", " philo.name, philo.age, mikey.name, mikey.age))" ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Philo is a mammal!\n" ] } ], "source": [ "# Is Philo a mammal?\n", "if philo.species == \"mammal\":\n", " print(\"{} is a {}!\".format(philo.name, philo.species))\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Instantiate the Dog object\n", "`philo = Dog(\"Philo\", 5)`\n", "`mikey = Dog(\"Mikey\", 6)`\n", "\n", "## Access the instance attributes\n", "`print(\"{} is {} and {} is {}.\".format(\n", " philo.name, philo.age, mikey.name, mikey.age))`\n", "\n", "# Is Philo a mammal?\n", "`if philo.species == \"mammal\":\n", " print(\"{0} is a {1}!\".format(philo.name, philo.species))`" ] }, { "cell_type": "code", "execution_count": 56, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Philo is 5 and Mikey is 6.\n", "Philo is a mammal!\n" ] } ], "source": [ "%run dog.py" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## What’s Going On?\n", "\n", "We created a new instance of the Dog() class and assigned it to the variable philo. We then passed it two arguments, \"Philo\" and 5, which represent that dog’s name and age, respectively.\n", "\n", "These attributes are passed to the __init__ method, which gets called any time you create a new instance, attaching the name and age to the object. You might be wondering why we didn’t have to pass in the self argument.\n", "\n", "This is Python magic; when you create a new instance of the class, Python automatically determines what self is (a Dog in this case) and passes it to the __init__ method." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Instance Methods\n", "\n", "Instance methods are defined inside a class and are used to get the contents of an instance. They can also be used to perform operations with the attributes of our objects. Like the `__init__` method, the first argument is always self:" ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Mikey the third is 6 years old\n", "Mikey the third says Wuff Wuff\n" ] } ], "source": [ "class Dog:\n", "\n", " # Class Attribute\n", " species = 'mammal'\n", "\n", " # Initializer / Instance Attributes\n", " def __init__(self, name, age):\n", " self.name = name\n", " self.age = age\n", "\n", " # instance method\n", " def description(self):\n", " return \"{} is {} years old\".format(self.name, self.age)\n", "\n", " # instance method\n", " def speak(self, sound):\n", " return \"{} says {}\".format(self.name, sound)\n", "\n", "# Instantiate the Dog object\n", "mikey = Dog(\"Mikey the third\", 6)\n", "\n", "# call our instance methods\n", "print(mikey.description())\n", "print(mikey.speak(\"Wuff Wuff\"))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "In the latter method, `speak()`, we are defining behavior. What other behaviors could you assign to a dog? Look back to the beginning paragraph to see some example behaviors for other objects." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Modifying Attributes\n", "\n", "You can change the value of attributes based on some behavior:" ] }, { "cell_type": "code", "execution_count": 60, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "class Student:\n", " def __init__(self):\n", " self.is_smart = False\n", " def learns(self):\n", " self.is_smart = True" ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "my_student = Student()" ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_student.is_smart" ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "my_student.learns()" ] }, { "cell_type": "code", "execution_count": 66, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_student.is_smart" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Python Object Inheritance\n", "\n", "**Inheritance** is the process by which one class takes on the attributes and methods of another. Newly formed classes are called **child classes**, and the classes that child classes are derived from are called **parent classes**.\n", "\n", "It’s important to note that child classes **override** or **extend** the functionality (e.g., attributes and behaviors) of parent classes. In other words, child classes inherit all of the parent’s attributes and behaviors but can also specify different behavior to follow. The most basic type of class is an object, which generally all other classes inherit as their parent.\n", "\n", "When you define a new class, Python 3 it implicitly uses object as the parent class. So the following two definitions are equivalent:" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "class Dog(object):\n", " pass\n", "\n", "# In Python 3, this is the same as:\n", "\n", "class Dog:\n", " pass\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Dog Park Example\n", "\n", "Let’s pretend that we’re at a dog park. There are multiple `Dog objects` engaging in `Dog behaviors`, each with different `attributes`. In regular-speak that means some dogs are running, while some are stretching and some are just watching other dogs. Furthermore, each dog has been named by its owner and, since each dog is living and breathing, each ages.\n", "\n", "What’s another way to differentiate one dog from another? How about the dog’s **breed**:" ] }, { "cell_type": "code", "execution_count": 70, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "class Dog:\n", " def __init__(self, breed):\n", " self.breed = breed" ] }, { "cell_type": "code", "execution_count": 71, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "spencer = Dog(\"German Shepard\")" ] }, { "cell_type": "code", "execution_count": 72, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "'German Shepard'" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "spencer.breed" ] }, { "cell_type": "code", "execution_count": 73, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "sara = Dog(\"Boston Terrier\")" ] }, { "cell_type": "code", "execution_count": 74, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "'Boston Terrier'" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sara.breed" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Each breed of dog has slightly different behaviors. To take these into account, let’s create separate classes for each breed. These are child classes of the parent Dog class.\n", "\n", "## Extending the Functionality of a Parent Class\n", "\n", "Create a new file called `dog_inheritance.py:`" ] }, { "cell_type": "code", "execution_count": 75, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Jim is 12 years old\n", "Jim runs slowly\n" ] } ], "source": [ "# Parent class\n", "class Dog:\n", "\n", " # Class attribute\n", " species = 'mammal'\n", "\n", " # Initializer / Instance attributes\n", " def __init__(self, name, age):\n", " self.name = name\n", " self.age = age\n", "\n", " # instance method\n", " def description(self):\n", " return \"{} is {} years old\".format(self.name, self.age)\n", "\n", " # instance method\n", " def speak(self, sound):\n", " return \"{} says {}\".format(self.name, sound)\n", "\n", "\n", "# Child class (inherits from Dog class)\n", "class RussellTerrier(Dog):\n", " def run(self, speed):\n", " return \"{} runs {}\".format(self.name, speed)\n", "\n", "\n", "# Child class (inherits from Dog class)\n", "class Bulldog(Dog):\n", " def run(self, speed):\n", " return \"{} runs {}\".format(self.name, speed)\n", "\n", "\n", "# Child classes inherit attributes and\n", "# behaviors from the parent class\n", "jim = Bulldog(\"Jim\", 12)\n", "print(jim.description())\n", "\n", "# Child classes have specific attributes\n", "# and behaviors as well\n", "print(jim.run(\"slowly\"))" ] }, { "cell_type": "code", "execution_count": 76, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Jim is 12 years old\n", "Jim runs slowly\n" ] } ], "source": [ "%run dog_inheritance.py" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "We haven’t added any special attributes or methods to differentiate a RussellTerrier from a Bulldog, but since they’re now two different classes, we could for instance give them different class attributes defining their respective speeds.\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Parent vs. Child Classes\n", "\n", "The `isinstance()` function is used to determine if an instance is also an instance of a certain parent class.\n", "\n", "Save this as `dog_isinstance.py:`" ] }, { "cell_type": "code", "execution_count": 80, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Jim is 12 years old\n", "Jim runs slowly\n", "True\n", "True\n", "False\n", "False\n" ] }, { "ename": "TypeError", "evalue": "isinstance() arg 2 must be a type or tuple of types", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 56\u001b[0m \u001b[0;31m# Is julie and instance of jim?\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 57\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mjulie\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mjim\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: isinstance() arg 2 must be a type or tuple of types" ] } ], "source": [ "# Parent class\n", "class Dog:\n", "\n", " # Class attribute\n", " species = 'mammal'\n", "\n", " # Initializer / Instance attributes\n", " def __init__(self, name, age):\n", " self.name = name\n", " self.age = age\n", "\n", " # instance method\n", " def description(self):\n", " return \"{} is {} years old\".format(self.name, self.age)\n", "\n", " # instance method\n", " def speak(self, sound):\n", " return \"{} says {}\".format(self.name, sound)\n", "\n", "\n", "# Child class (inherits from Dog() class)\n", "class RussellTerrier(Dog):\n", " def run(self, speed):\n", " return \"{} runs {}\".format(self.name, speed)\n", "\n", "\n", "# Child class (inherits from Dog() class)\n", "class Bulldog(Dog):\n", " def run(self, speed):\n", " return \"{} runs {}\".format(self.name, speed)\n", "\n", "\n", "# Child classes inherit attributes and\n", "# behaviors from the parent class\n", "jim = Bulldog(\"Jim\", 12)\n", "print(jim.description())\n", "\n", "# Child classes have specific attributes\n", "# and behaviors as well\n", "print(jim.run(\"slowly\"))\n", "\n", "# Is jim an instance of Dog()?\n", "print(isinstance(jim, Dog))\n", "\n", "# Is julie an instance of Dog()?\n", "julie = Dog(\"Julie\", 100)\n", "print(isinstance(julie, Dog))\n", "\n", "# Is johnny walker an instance of Bulldog()\n", "johnnywalker = RussellTerrier(\"Johnny Walker\", 4)\n", "print(isinstance(johnnywalker, Bulldog))\n", "\n", "# Is julie and instance of jim?\n", "print(isinstance(julie, Bulldog))\n", "\n", "# Is julie and instance of jim?\n", "print(isinstance(julie, jim))" ] }, { "cell_type": "code", "execution_count": 81, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Jim is 12 years old\n", "Jim runs slowly\n", "True\n", "True\n", "False\n", "False\n" ] }, { "ename": "TypeError", "evalue": "isinstance() arg 2 must be a type or tuple of types", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m~/Work/teaching/TUChemnitz/SciCompPython/dog_isinstance.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 56\u001b[0m \u001b[0;31m# Is julie and instance of jim?\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 57\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 58\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mjulie\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mjim\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: isinstance() arg 2 must be a type or tuple of types" ] } ], "source": [ "%run dog_isinstance.py" ] }, { "cell_type": "code", "execution_count": 82, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Enter side:1 : 3\n", "Enter side:2 : 4\n", "Enter side:3 : 5\n", "Side 1 is 3.0\n", "Side 2 is 4.0\n", "Side 3 is 5.0\n" ] } ], "source": [ "# Parent class\n", "class Polygon:\n", "\n", " # Class attribute\n", " \n", " # Initializer / Instance attributes\n", " def __init__(self, no_of_sides):\n", " self.n = no_of_sides\n", " self.sides = [0 for i in range(no_of_sides)]\n", "\n", " # instance method\n", " def inputSides(self):\n", " self.sides = [float(input(\"Enter side:\"+str(i+1)+\" : \")) for i in range(self.n)]\n", "\n", " # instance method\n", " def dispSides(self):\n", " for i in range(self.n):\n", " print(\"Side\",i+1,\"is\",self.sides[i])\n", " \n", "p = Polygon(3)\n", "\n", "p.inputSides()\n", "p.dispSides()" ] }, { "cell_type": "code", "execution_count": 83, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "class Triangle(Polygon):\n", " def __init__(self):\n", " Polygon.__init__(self,3)\n", " def findArea(self):\n", " a, b, c = self.sides\n", " # calculate the semi-perimeter\n", " s = (a + b + c) / 2\n", " area = (s*(s-a)*(s-b)*(s-c)) ** 0.5\n", " print('The area of the triangle is %0.2f' %area)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "So lets try the triangle thing out.\n" ] }, { "cell_type": "code", "execution_count": 85, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Enter side:1 : 3\n", "Enter side:2 : 4\n", "Enter side:3 : 5\n" ] } ], "source": [ "t=Triangle()\n", "t.inputSides()" ] }, { "cell_type": "code", "execution_count": 86, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Side 1 is 3.0\n", "Side 2 is 4.0\n", "Side 3 is 5.0\n" ] } ], "source": [ "t.dispSides()" ] }, { "cell_type": "code", "execution_count": 87, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The area of the triangle is 6.00\n" ] } ], "source": [ "t.findArea()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Method Overriding in Python\n", "\n", "In the above example, notice that `__init__()` method was defined in both classes, Triangle as well Polygon. When this happens, the method in the derived class overrides that in the base class. This is to say, `__init__()` in Triangle gets preference over the same in Polygon.\n", "\n", "Generally when overriding a base method, we tend to extend the definition rather than simply replace it. The same is being done by calling the method in base class from the one in derived class (calling `Polygon.__init__()` from `__init__()` in Triangle).\n", "\n", "A better option would be to use the built-in function super(). So, super().`__init__(3)` is equivalent to Polygon.`__init__(self,3)` and is preferred. You can learn more about the super() function in Python.\n", "\n", "Two built-in functions `isinstance()` and `issubclass()` are used to check inheritances. Function `isinstance()` returns `True` if the object is an instance of the class or other classes derived from it. Each and every class in Python inherits from the base class object." ] }, { "cell_type": "code", "execution_count": 97, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The mobile is: Apple\n", "The RAM is: 2\n", "The storage is: 64\n", "The model is: iPhone X\n" ] } ], "source": [ "class Computer():\n", " def __init__(self, computer, ram, storage):\n", " self.computer = computer\n", " self.ram = ram\n", " self.storage = storage\n", "\n", "# Class Mobile inherits Computer\n", "class Mobile(Computer):\n", " def __init__(self, computer, ram, storage, model):\n", " super().__init__(computer, ram, storage)\n", " self.model = model\n", "\n", "Apple = Mobile('Apple', 2, 64, 'iPhone X')\n", "print('The mobile is:', Apple.computer)\n", "print('The RAM is:', Apple.ram)\n", "print('The storage is:', Apple.storage)\n", "print('The model is:', Apple.model)" ] }, { "cell_type": "code", "execution_count": 88, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isinstance(t,Triangle)" ] }, { "cell_type": "code", "execution_count": 89, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isinstance(t,Polygon)" ] }, { "cell_type": "code", "execution_count": 90, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isinstance(t,int)" ] }, { "cell_type": "code", "execution_count": 91, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isinstance(t,object)" ] }, { "cell_type": "code", "execution_count": 92, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isinstance(t,Polygon)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Similarly, `issubclass()` is used to check for class inheritance." ] }, { "cell_type": "code", "execution_count": 93, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "issubclass(Polygon,Triangle)" ] }, { "cell_type": "code", "execution_count": 94, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "issubclass(Triangle,Polygon)" ] }, { "cell_type": "code", "execution_count": 95, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 95, "metadata": {}, "output_type": "execute_result" } ], "source": [ "issubclass(bool,int)" ] }, { "cell_type": "code", "execution_count": 96, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "issubclass(int,bool)" ] } ], "metadata": { "anaconda-cloud": {}, "celltoolbar": "Slideshow", "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.7.6" } }, "nbformat": 4, "nbformat_minor": 2 }