{ "metadata": { "name": "", "signature": "sha256:02a535e81b46e9c03a4d67807c160f8502e2bd334f91df67435ce73bc6f3d127" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# An Introduction to Objects & Object-Oriented Programming in Python (& Sundry Advanced Topics)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "# Programming Paradigms\n", "\n", "As it goes for most scientific methods, programming also has different paradigms associated with it, based on the thought process of the programmer. \n", "\n", "![Programming Paradigms](http://www.willamette.edu/~fruehr/haskell/pics/Paradigms.png)\n", "\n", "Today's lesson will walk you through some of these paradigms, focusing on Object Oriented Programming for the better part.\n", "## Contents\n", "- [Programming Paradigms](#intro)\n", "- [Procedural Programming](#mpl)\n", " - [Review of Functions](#review)\n", " - [Excerise 1](#Ex1)\n", "- [Object Oriented Programming](#oop)\n", " - [Motivation](#motiv)\n", " - [String objects](#sobjects)\n", " - [Exercise 2](#Ex2)\n", " - [Dictionaries and Lists](#DL)\n", " - [Iterables](#iter)\n", " - [List Comprhensions](#lc)\n", " - [Nested List Comprehensions](#nlc)\n", " - [Dictionaries](#dict)\n", " - [Namespaces](#ns) \n", " - [Your own objects](#own)\n", " - [Exercise 3](#Ex3)\n", "- [Objects, Part II](#oop2)\n", " - [Private Variables](#priv)\n", " - [Destructor](#dest)\n", " - [Inheritance](#inherit)\n", " - [Exercise 4](#Ex4)\n", "- [Functional Programming](#func)\n", "- [pip](#pip)\n", "- [Numerical example](#num)\n", "- [References](#refs)\n", "- [Credits](#credits)\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from __future__ import division\n", "\n", "import numpy as np\n", "import scipy as sp\n", "import matplotlib as mpl\n", "import matplotlib.pyplot as plt\n", "\n", "#IPython magic command for inline plotting\n", "%matplotlib inline\n", "#a better plot shape for IPython\n", "mpl.rcParams['figure.figsize']=[15,3]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 16 }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "## Procedural Programming\n", "**Imperative programming** is a programming paradigm that describes computation in terms of statements that change a program state. In imperative programming, you tell the computer what to do. \"Computer, add x and y,\" or \"Computer, slap a dialog box onto the screen.\" The focus is on what steps the computer should take rather than what the computer will do (ex. C, C++, Java).\n", "\n", "**Structured programming** is any programming when functionality is divided into units like for loop, while loop, if... then etc block structure.\n", "\n", "**Procedural programming** is a programming paradigm, derived from structured programming, based upon the concept of the procedure call. Procedures, also known as routines, subroutines, methods, or functions, contain a series of computational steps to be carried out. Any given procedure might be called at any point during a program's execution.\n", "\n", "![Procedural Programming](http://i.stack.imgur.com/Ip5eR.jpg)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Review of functions\n", "\n", "The structure of a function is\n", " #def function_name(input arguments):\n", " #function defintion\n", " #return output\n", " \n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "#Example to find the area of a square\n", "def areaSquare(a):\n", " return a ** 2\n", "\n", "print areaSquare(3)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "9\n" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Exercise 1\n", "- Write a function, `sumArray`, which takes an array of numbers as the input and returns the sum of the array. (Use the NumPy documentation if you need to.)" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use this array to test the function you just wrote." ] }, { "cell_type": "code", "collapsed": false, "input": [ "x=np.linspace(1,10,10)\n", "print x\n", "print sumArray(x)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "---\n", "## Object Oriented Programming\n", "\n", "\n", "### Motivation for Object-Oriented Programming\n", "\n", "A programming _object_ is a data structure which seeks to model the real world by associating parameters and functions in a natural way. For instance, when you interact with your car, you don't think of an abstract button before changing your radio station, nor do you think of an abstract radio. You simply press the button on the radio. Similarly with code, it is often more natural to say `car.radio.freq.up()` than `increment(frequency(radio(car))))`, although both could be possible ways of thinking of the problem.\n", "\n", "_Object-oriented programming_ is thus a way of thinking about programs in terms of natural models. Each object possesses its own _member variables_ and _methods_, which are functions as a part of the object. An example:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "#Pen.py \n", "class Pen(object):\n", " def __init__ (self):\n", " self.state = False\n", "\n", " def click(self):\n", " self.state = not self.state\n", "\n", " def write(self, in_str):\n", " if (self.state):\n", " print \"Writing message '%s'.\\n\"%in_str;\n", " else:\n", " print \"Oops! The pen is retracted.\\n\";\n" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 17 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This defines a possible object, or _class_, without actually creating one. Think of this as a Platonic archetype, if you're into that sort of thing; or else just as \"the idea of\" a pen, rather than an actual pen. To use an actual pen, we have to create it and then manipulate it:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "bic = Pen();\n", "\n", "bic.click();\n", "bic.write(\"hello world\");\n", "print bic.state" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Writing message 'hello world'.\n", "\n", "True\n" ] } ], "prompt_number": 18 }, { "cell_type": "markdown", "metadata": {}, "source": [ "As another example, consider the following scenario.\n", "\n", "Bob and John are two students enrolled in CS 999\u2014User Interface Design. The professor for the course has given them a simple task as a part of developing an educational computer game for kids:\n", "\n", "- There will be three shapes displayed (triangle, square, and circle).\n", "- When the user clicks on one, it will display its area and circumference (perimeter). \n", "\n", "Both of them head to the library and start coding away. Here's what Bob-the-procedure-lover's code looks like:\n", "\n", " # Bob's code\n", " def area(shape):\n", " #Code to find the area for a shape\n", " \n", " def circum(shape):\n", " #Code to find the circumference of the shape\n", "\n", "Here is what John-the-OOP-guy wrote for his task:\n", "\n", " # John's code\n", " class Square:\n", " def area():\n", " #Code to find area of square\n", " def circum():\n", " #Code to find circumference of square\n", "\n", " class Circle:\n", " def area():\n", " #Code to find area of circle\n", " def circum():\n", " #Code to find circumference of circle\n", "\n", " class Triangle:\n", " def area():\n", " #Code to find area of triangle\n", " def circum():\n", " #Code to find circumference of triangle\n", "\n", "Both of them test their code extensively and hand it in.\n", "\n", "On the outside, it might seem like a more cumbersome task to define an **object** for each of the shapes and Bob, our procedural guy, seems to have the slick solution.\n", "\n", "But now (plot twist!), the professor pats both of them on the back and says, \"That was too easy. Now let's add an amoeba shape to the list of shapes and find its area and circumference too.\" Bob is slightly flustered but manages to alter his code by doing the following:\n", "\n", " # Bob's code\n", " def area(shape):\n", " if shape!=Amoeba:\n", " #Code to find the area for a shape\n", " else:\n", " #Code to find amoeba specific area\n", "\n", " def circum(shape):\n", " if shape!=Amoeba:\n", " #Code to find the circumference for a shape\n", " else:\n", " #Code to find amoeba specific circumference\n", "\n", "Bob seemed okay with his work but it still unnerved him because he had to modify his **previously tested code** and any spec change would force him to do so again. John is less worried because all he has to do is use another *class* to define an amoeba.\n", "\n", " # John's code\n", " class Amoeba:\n", " def area():\n", " #Code to find area of amoeba\n", " def circum():\n", " #Code to find circumference of amoeba\n", "\n", "But the the professor was not done (are they ever? :). He came up to them and said, \"Guys, sorry I forgot to mention this before, but I need you to approximate the area of your amoeba using the mid-point method.\"\n", "\n", "On hearing this Bob gets quite worked up and furiously modifies his code and yet again ends up having to change the twice-modified, twice-tested code.\n", "\n", " # Bob's code\n", " def area(shape,midpoint):\n", " if shape!=Amoeba:\n", " #Code to find the area for a shape\n", " else:\n", " #Use the midpoint of the amoeba to find the area\n", "\n", " def circum(shape):\n", " if shape!=Amoeba:\n", " #Code to find the circumference for a shape\n", " else:\n", " #Code to find amoeba specific circumference\n", "\n", "While for John it is a piece of cake, because he only has to modify the methods for the amoeba *class*.\n", "\n", " # John's code\n", " class Amoeba:\n", " def area(midpoint):\n", " #Code to find area of amoeba using midpoint\n", " def circum():\n", " #Code to find circumference of amoeba\n", "\n", "This brings us back around to the initial question\u2014why OOP? Object-oriented programming:\n", "\n", "- Makes your code more dynamic\n", "- Leaves your tested code untouched.\n", "- Has more cool features (and words) associated with it such as inheritance, abstraction, encapsulation etc. which we will go into.\n", "\n", "For now I hope we have convinced you sufficiently enough to take a trip with us to Objectville!\n", "\n", "![](http://www.safaribooksonline.com/library/view/head-first-javascript/9781449340124/httpatomoreillycomsourceoreillyimages1997343.png.jpg)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Strictly speaking, you've been working with objects in Python for a while even if you didn't realize it: lists, tuples, and dictionaries are all objects. Indeed, anything which uses a _method_, or member function, is an object in Python; thus `my_string.upper()` or even `'philadelphia'.capitalize()` are examples of string objects. Let's examine strings in more detail first." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "### String Objects\n", "\n", "As mentioned, strings are one of the most common examples of objects in Python, and they offer a number of illustrative and useful methods. Most of your classes will not need to be this versatile, but strings are still a prime example of how much to offer the user in terms of built-in functions." ] }, { "cell_type": "code", "collapsed": false, "input": [ "my_string = 'sunday sunday sunday'\n", "my_string.upper()" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 19, "text": [ "'SUNDAY SUNDAY SUNDAY'" ] } ], "prompt_number": 19 }, { "cell_type": "code", "collapsed": false, "input": [ "'philadelphia'.capitalize()" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 20, "text": [ "'Philadelphia'" ] } ], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": [ "# The following use of a member method `join` is astonishingly useful.\n", "elements = ['fire', 'earth', 'water', 'air']\n", "', '.join(elements)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 21, "text": [ "'fire, earth, water, air'" ] } ], "prompt_number": 21 }, { "cell_type": "code", "collapsed": false, "input": [ "# As is the use of `split`, particularly in data processing.\n", "pmu_data = '03-Apr-2014 00:55:07.500,60.0347,Good,0,Good,0,Good,121.275,Good,102.8688,Good,60.0353,Good,0,Good,0,Good,60.035,Good,0,Good,0,Good,123.285,Good,14.69637,Good,123.783,Good,50.32861,Good,0,Good,60.035,Good,0.01,Good,0,Good,112.985,Good,162.6308,Good,0.1530308,Good,132.8789,Good'\n", "pmu_data.split(',')" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 22, "text": [ "['03-Apr-2014 00:55:07.500',\n", " '60.0347',\n", " 'Good',\n", " '0',\n", " 'Good',\n", " '0',\n", " 'Good',\n", " '121.275',\n", " 'Good',\n", " '102.8688',\n", " 'Good',\n", " '60.0353',\n", " 'Good',\n", " '0',\n", " 'Good',\n", " '0',\n", " 'Good',\n", " '60.035',\n", " 'Good',\n", " '0',\n", " 'Good',\n", " '0',\n", " 'Good',\n", " '123.285',\n", " 'Good',\n", " '14.69637',\n", " 'Good',\n", " '123.783',\n", " 'Good',\n", " '50.32861',\n", " 'Good',\n", " '0',\n", " 'Good',\n", " '60.035',\n", " 'Good',\n", " '0.01',\n", " 'Good',\n", " '0',\n", " 'Good',\n", " '112.985',\n", " 'Good',\n", " '162.6308',\n", " 'Good',\n", " '0.1530308',\n", " 'Good',\n", " '132.8789',\n", " 'Good']" ] } ], "prompt_number": 22 }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Unicode Strings**\n", "\n", "In Python 2, Unicode strings, or strings containing special characters beyond a certain limited set, must be explicitly marked as such. In Python 3, this restriction is gone and all strings are Unicode strings.\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "u'\u5df1\u6240\u4e0d\u6b32\uff0c\u52ff\u65bd\u65bc\u4eba\u3002 (\u5b54\u592b\u5b50)'\n", "#print u'\u5df1\u6240\u4e0d\u6b32\uff0c\u52ff\u65bd\u65bc\u4eba\u3002 (\u5b54\u592b\u5b50)'" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 23, "text": [ "u'\\u5df1\\u6240\\u4e0d\\u6b32\\uff0c\\u52ff\\u65bd\\u65bc\\u4eba\\u3002 (\\u5b54\\u592b\\u5b50)'" ] } ], "prompt_number": 23 }, { "cell_type": "code", "collapsed": false, "input": [ "u'S\u00e3o Paolo, Brasil'\n", "#print u'S\u00e3o Paolo, Brasil'" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 24, "text": [ "u'S\\xe3o Paolo, Brasil'" ] } ], "prompt_number": 24 }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Raw Strings**\n", "\n", "It is occasionally useful to write strings without escaping backslashes lying everywhere. Two cases that come to mind are hard-coded path names (`r'C:\\Python27\\Tools\\Scripts\\2to3.py'`) (incidentally normally a bad idea) and LaTeX strings (`r'\\frac{d}{dx}\\left(u(x)v(x)\\right)'`)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "print \"\\tTab me over\"\n", "print r\"\\tDon't tab me over\"" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\tTab me over\n", "\\tDon't tab me over\n" ] } ], "prompt_number": 25 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Exercise 2\n", "\n", "- The following code loads a string of uppercase alphabet characters. Convert this string into a lowercase comma-delimited string in one line of code (_i.e._, `'a,b,c,...'`)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from string import ascii_uppercase\n", "ascii_uppercase" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 26, "text": [ "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" ] } ], "prompt_number": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "## Dictionaries & Lists as Objects\n", "\n", "Python by design provides a number of convenient functions for working with dictionaries and lists. We have worked with some of these methods in the past. \n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = [66.25, 333, 333, 1, 1234.5]\n", "a.insert(2, -1)\n", "a.append(333)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 27 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "### Iterables\n", "\n", "When it comes to dividing groups into pieces, many objects work \"naturally\" in Python. For instance:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "dogs = ['newfoundland', 'labrador', 'chow-chow', 'mutt']\n", "print 'I have %d dogs.'%len(dogs)\n", "for dog in dogs:\n", " print 'One kind of dog is a %s.'%dog" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "I have 4 dogs.\n", "One kind of dog is a newfoundland.\n", "One kind of dog is a labrador.\n", "One kind of dog is a chow-chow.\n", "One kind of dog is a mutt.\n" ] } ], "prompt_number": 28 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### List Comprehension\n", "\n", "List comprehensions provide a concise way to create lists. Common applications are to make new lists where each element is the result of some operations applied to each member of another sequence or iterable, or to create a subsequence of those elements that satisfy a certain condition.\n", "\n", "For example, assume we want to create a list of squares, like:\n", "\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "squares = []\n", "for x in range(10):\n", " squares.append(x**2)\n", "\n", "squares\n", "\n", "#Same as\n", "squares = [x**2 for x in range(10)]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 13 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Nested List Comprehensions\n", "\n", "The list comprehension operations can be exteneded to multi-dimensional lists too.\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ " matrix = [ [1, 2, 3, 4],\n", " [5, 6, 7, 8],\n", " [9, 10, 11, 12],\n", "]\n", " \n", "#List comprehension to evaluate transpose\n", "[[row[i] for row in matrix] for i in range(4)]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 29, "text": [ "[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]" ] } ], "prompt_number": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Dictionaries\n", "\n", "Another useful data type built into Python is the dictionary. It is best to think of a dictionary as an unordered set of key: value pairs, with the requirement that the keys are unique (within one dictionary). A pair of braces creates an empty dictionary: {}. Placing a comma-separated list of *key:value* pairs within the braces adds initial key:value pairs to the dictionary; this is also the way dictionaries are written on output.\n", "\n", "The main operations on a dictionary are storing a value with some key and extracting the value given the key. \n", "\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "myfirstdict = {'a':1, 'b':2, 'c':3}\n", "\n", "myfirstdict['a']" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 11, "text": [ "1" ] } ], "prompt_number": 11 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Names, Namespaces, and Magic\n", "\n", "Occasionally you may have encountered odd phrases in Python, such as `if __name__ == \"__main__\":`. These are _reserved names_, which carry various special meanings to Python. (For instance, when you access a member variable in a function, you are (sometimes) actually invoking a function `__get_attr__` to access the variable.)\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "bic.__dict__" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 30, "text": [ "{'state': True}" ] } ], "prompt_number": 30 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Incidentally, this is how you implement [_operator overloading_](https://docs.python.org/2/reference/datamodel.html#object.__lt__), but we'll leave this for now and touch on it again at the end." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "## Your Own Objects\n", "\n", "Now that we've seen what you can do with objects, let's design our own classes. A _class_ is a sort of template defining an _object_, which is _instantiated_ from a class and is a _class instance_. (I apologize for the terminology, as I had nothing to do with it's making. :)\n", "\n", "Objects are clearly models of the real world. Some examples include:\n", "\n", "- Student: name, age, sex, GPA, netid\n", "- Employee: department, salary, bonus\n", "- Mechanical objects: fans, tables, vehicles, just about anything\n", "\n", "![](http://upload.wikimedia.org/wikipedia/commons/thumb/9/98/CPT-OOP-objects_and_classes_-_attmeth.svg/300px-CPT-OOP-objects_and_classes_-_attmeth.svg.png)\n", "\n", "There are two important things to know about an **object**:\n", "\n", "- Things an object knows about itself are called **attributes**.\n", "- Things an object can do are called **methods**.\n", "\n", "So returning to the notion of a _class_: *a class is a blueprint for an object*. It tells the machine how to make an object of that particular type. Each object made from that class has its own values for the attributes of that class. (For example, you might use the Student class to make dozens of different students, and each student might have his own name, netID, GPA etc.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A Basic Object" ] }, { "cell_type": "code", "collapsed": false, "input": [ "class Dog:\n", " breed='abc'\n", " size=0\n", " name='xyz'" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 31 }, { "cell_type": "code", "collapsed": false, "input": [ "# Now let's create an object or an instance of the class Dog\n", "d=Dog()\n", "\n", "# The dot operator (.) gives you access to an object\u2019s state and behavior (instance variables and methods).\n", "d.name= 'Jack'\n", "print d.name" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Jack\n" ] } ], "prompt_number": 32 }, { "cell_type": "code", "collapsed": false, "input": [ "# Now let us add a method to the class\n", "class Dog:\n", " breed='abc'\n", " size=0\n", " name='xyz'\n", " \n", " def bark(self):\n", " print \"Ruff Ruff!\"" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 34 }, { "cell_type": "code", "collapsed": false, "input": [ "d=Dog()\n", "d.bark()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Ruff Ruff!\n" ] } ], "prompt_number": 35 }, { "cell_type": "markdown", "metadata": {}, "source": [ "In practice, wherever you write `self` in your method, when you run the method that `self` is replaced by the name of the object, so when we call `d.bark()` the `self` is replaced by `d`. To understand this better, let us define another instance of `Dog` called `x`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "x=Dog()\n", "x.bark()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Ruff Ruff!\n" ] } ], "prompt_number": 36 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Methods are similar to functions except that the first argument is usually `self` to reference any internal class attributes. We saw that we can alter the attribute values for an instance of a class by using the dot operator." ] }, { "cell_type": "code", "collapsed": false, "input": [ "x.name = 'Wolverine'\n", "x.breed = 'hound'\n", "size = 24 # inches tall at the shoulder" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Rather than define every piece separately, it is more convenient to use the _constructor_." ] }, { "cell_type": "code", "collapsed": false, "input": [ "class Dog:\n", " ''' Attributes include breed, size and name'''\n", " \n", " # constructor\n", " def __init__(self, name='xyz', breed='abc', size=0):\n", " self.name= name\n", " self.breed= breed\n", " self.size= size\n", " \n", " def bark(self):\n", " print \"Ruff Ruff!\"" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 37 }, { "cell_type": "code", "collapsed": false, "input": [ "y=Dog('Jack','lab',10)\n", "print y.name\n", "print y.breed\n", "\n", "y=Dog()\n", "print y.name\n", "print y.breed" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Jack\n", "lab\n", "xyz\n", "abc\n" ] } ], "prompt_number": 38 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Exercise 3\n", "\n", "- Define a class `Canvas` with attributes `width` and `length`. Write two methods, `dims()` to display `width` and `length` of the canvas and `area()` to return the area of the canvas as `width*length`. Remember to include a constructor method to input the values of length and width." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That's it for the basics. We'll address deeper questions like inheritance and private variables in Objects Part 2." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "## Objects, Part 2\n", "\n", "Now that you know a bit more about how objects go together and how several kinds of objects work in Python, let's take another look at the class definition itself.\n", "\n", "\n", "**Private Variables**\n", "\n", "In Python, you never declare variables, so there isn't an obvious way to hide them from outside users of your code (or make them _private_). If you haven't programmed with objects before, this may seem pointless, but there are actually good reasons for concealing internal state variables from users since it prevents them from mucking up your code, for instance. How do we actually make something private then?\n", "\n", "(_Encapsulation_, or data hiding, is the technical term for this: it hides variables except from certain related classes or from everything except the object itself. It's a good practice if you are concerned about concealing or glossing over complex behavior.) Consider the class `Account`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "class Account:\n", " def __init__(self, holder, number, balance, credit_line=1500): \n", " self.holder = holder \n", " self.number = number \n", " self.balance = balance\n", " self.credit_line = credit_line\n", " def deposit(self, amount): \n", " self.balance = amount\n", "\n", "acct = Account('Carrie Fisher', '492727ZED', 1300)\n", "print acct.holder, acct.number, acct.balance, acct.credit_line" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Carrie Fisher 492727ZED 1300 1500\n" ] } ], "prompt_number": 39 }, { "cell_type": "markdown", "metadata": {}, "source": [ "For good reasons, we would not want to be able to access all the details of this class directly from an instance or sometimes even from a *child* class. When we need to perform this kind of *data hiding*, we use the following type of attributes/methods. To hide these values from outside access, simply prefix them with the appropriate number of underscores `_`.\n", "\n", "
Name | \n", "Notation | \n", "Scope | \n", "
---|---|---|
Public | \n", "`name` | \n", "visible everywhere | \n", "
Protected | \n", "`_name` | \n", "accessible only by children and within object | \n", "
Private | \n", "`__name` | \n", "accessible only within object | \n", "