{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "cell_style": "center", "slideshow": { "slide_type": "slide" } }, "source": [ "# Objects" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" }, "tags": [ "remove-cell" ] }, "source": [ "**CS1302 Introduction to Computer Programming**\n", "___" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2020-11-27T11:20:04.656873Z", "start_time": "2020-11-27T11:20:04.651575Z" }, "slideshow": { "slide_type": "fragment" }, "tags": [ "remove-cell" ] }, "outputs": [ { "data": { "text/html": [ "
Manim Community v0.11.0\n",
       "\n",
       "
\n" ], "text/plain": [ "Manim Community \u001b[32mv0.\u001b[0m\u001b[32m11.0\u001b[0m\n", "\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from manim import *\n", "\n", "%reload_ext mytutor" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**Why object-oriented programming?**" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%manim -ql --progress_bar=none --disable_caching --flush_cache -v ERROR HelloWorld\n", "class HelloWorld(Scene):\n", " def construct(self):\n", " self.play(Write(Text(\"Hello, World!\")))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The above code defines\n", " - `HelloWorld` as a `Scene`\n", " - `construct`ed by \n", " - `play`ing an animation that `Write`\n", " - the `Text` message `'Hello, World!'`. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**Exercise** Try changing\n", "- Mobjects: `Text('Hello, World!')` to `MathTex(r'\\int tan(x)\\,dx = -\\ln(\\cos(x))')` or `Circle()` or `Square()`.\n", "- Animation objects: `Write` to `FadeIn` or `GrowFromCenter`.\n", "\n", "See the [documentation](https://docs.manim.community/) and [tutorial](https://talkingphysics.wordpress.com/2019/01/08/getting-started-animating-with-manim-and-python-3-7/) for other choices." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "More complicated behavior can be achieved by using different objects." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2020-09-27T11:30:40.028382Z", "start_time": "2020-09-27T11:30:40.020250Z" }, "code_folding": [ 0 ], "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/html": [ "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%html\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**What is an object?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Almost everything is an [`object`](https://docs.python.org/3/library/functions.html?highlight=object#object) in Python." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T11:55:23.765015Z", "start_time": "2020-10-09T11:55:23.702114Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(True, True, True)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isinstance?\n", "isinstance(1, object), isinstance(1.0, object), isinstance(\"1\", object)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "A function is also a [first-class](https://en.wikipedia.org/wiki/First-class_function) object object." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "ExecuteTime": { "end_time": "2020-09-26T14:12:33.321836Z", "start_time": "2020-09-26T14:12:33.315596Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(True, True)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isinstance(print, object), isinstance(\"\".isdigit, object)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "A data type is also an object." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "ExecuteTime": { "end_time": "2020-09-26T14:14:42.838068Z", "start_time": "2020-09-26T14:14:42.833683Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(True, True, True)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# chicken and egg relationship\n", "isinstance(type, object), isinstance(object, type), isinstance(object, object)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Python is a [*class-based* object-oriented programming](https://en.wikipedia.org/wiki/Object-oriented_programming#Class-based_vs_prototype-based) language: \n", "- Each object is an instance of a *class* (also called type in Python).\n", "- An object is a collection of *members/attributes*, each of which is an object." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T11:56:26.157925Z", "start_time": "2020-10-09T11:56:26.136101Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "hasattr?\n", "hasattr(str, \"isdigit\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Different objects of a class\n", "- have the same set of attributes as that of the class, but\n", "- the attribute values can be different." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T11:56:51.756366Z", "start_time": "2020-10-09T11:56:51.737117Z" }, "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(True, True)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dir?\n", "dir(1) == dir(int), complex(1, 2).imag != complex(1, 1).imag" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**How to operate on an object?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- A class can define a function as an attribute for all its instances. \n", "- Such a function is called a *method* or *member function*." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T11:57:39.967209Z", "start_time": "2020-10-09T11:57:39.960448Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "((1-2j), method_descriptor)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "complex.conjugate(complex(1, 2)), type(complex.conjugate)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "A [method](https://docs.python.org/3/tutorial/classes.html#method-objects) can be accessed by objects of the class:" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "ExecuteTime": { "end_time": "2020-09-26T15:27:25.840387Z", "start_time": "2020-09-26T15:27:25.833835Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "((1-2j), builtin_function_or_method)" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "complex(1, 2).conjugate(), type(complex(1, 2).conjugate)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "`complex(1,2).conjugate` is a *callable* object:\n", "- Its attribute `__self__` is assigned to `complex(1,2)`.\n", "- When called, it passes `__self__` as the first argument to `complex.conjugate`." ] }, { "cell_type": "code", "execution_count": 85, "metadata": { "ExecuteTime": { "end_time": "2020-09-27T11:48:08.273598Z", "start_time": "2020-09-27T11:48:08.265782Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(True, (1+2j))" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "callable(complex(1, 2).conjugate), complex(1, 2).conjugate.__self__" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## File Objects" ] }, { "cell_type": "markdown", "metadata": { "ExecuteTime": { "end_time": "2020-07-25T05:29:37.415351Z", "start_time": "2020-07-25T05:29:37.409512Z" }, "slideshow": { "slide_type": "subslide" } }, "source": [ "**How to read a text file?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Consider reading a csv (comma separated value) file:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T11:58:17.840881Z", "start_time": "2020-10-09T11:58:17.700467Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "name, email, phone\r\n", "Amelia Hawkins,dugorre@lufu.cg,(414) 524-6465\r\n", "Alta Perez,bos@fiur.sc,(385) 247-9001\r\n", "Tai Ming Chan,tmchan@cityu.edu.hk,(634) 234-7294\r\n", "Annie Zimmerman,okodag@saswuf.mn,(259) 862-1082\r\n", "Eula Crawford,ve@rorohte.mx,(635) 827-9819\r\n", "Clayton Atkins,vape@nig.eh,(762) 271-7090\r\n", "Hallie Day,kozzazazi@ozakewje.am,(872) 949-5878\r\n", "Lida Matthews,joobu@pabnesis.kg,(213) 486-8330\r\n", "Amelia Pittman,nulif@uposzag.au,(800) 303-3234\r\n" ] } ], "source": [ "!more 'contact.csv'" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "To read the file by a Python program:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2020-09-27T14:34:46.544864Z", "start_time": "2020-09-27T14:34:46.538505Z" }, "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "name, email, phone\n", "Amelia Hawkins,dugorre@lufu.cg,(414) 524-6465\n", "Alta Perez,bos@fiur.sc,(385) 247-9001\n", "Tai Ming Chan,tmchan@cityu.edu.hk,(634) 234-7294\n", "Annie Zimmerman,okodag@saswuf.mn,(259) 862-1082\n", "Eula Crawford,ve@rorohte.mx,(635) 827-9819\n", "Clayton Atkins,vape@nig.eh,(762) 271-7090\n", "Hallie Day,kozzazazi@ozakewje.am,(872) 949-5878\n", "Lida Matthews,joobu@pabnesis.kg,(213) 486-8330\n", "Amelia Pittman,nulif@uposzag.au,(800) 303-3234\n" ] } ], "source": [ "f = open(\"contact.csv\") # create a file object for reading\n", "print(f.read()) # return the entire content\n", "f.close() # close the file" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "1. [`open`](https://docs.python.org/3/library/functions.html?highlight=open#open) is a function that creates a file object and assigns it to `f`.\n", "1. Associated with the file object: \n", " - [`read`](https://docs.python.org/3/library/io.html#io.TextIOBase.read) returns the entire content of the file as a string.\n", " - [`close`](https://docs.python.org/3/library/io.html#io.IOBase.close) flushes and closes the file." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Why close a file?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "If not, depending on the operating system,\n", "- other programs may not be able to access the file, and\n", "- changes may not be written to the file." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "To ensure a file is closed properly, we can use the [`with` statement](https://docs.python.org/3/reference/compound_stmts.html#with):" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2020-09-27T14:34:53.564370Z", "start_time": "2020-09-27T14:34:53.556338Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "name, email, phone\n", "Amelia Hawkins,dugorre@lufu.cg,(414) 524-6465\n", "Alta Perez,bos@fiur.sc,(385) 247-9001\n", "Tai Ming Chan,tmchan@cityu.edu.hk,(634) 234-7294\n", "Annie Zimmerman,okodag@saswuf.mn,(259) 862-1082\n", "Eula Crawford,ve@rorohte.mx,(635) 827-9819\n", "Clayton Atkins,vape@nig.eh,(762) 271-7090\n", "Hallie Day,kozzazazi@ozakewje.am,(872) 949-5878\n", "Lida Matthews,joobu@pabnesis.kg,(213) 486-8330\n", "Amelia Pittman,nulif@uposzag.au,(800) 303-3234\n" ] } ], "source": [ "with open(\"contact.csv\") as f:\n", " print(f.read())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The `with` statement applies to any [context manager](https://docs.python.org/3/reference/datamodel.html#context-managers) that provides the methods\n", "- `__enter__` for initialization, and\n", "- `__exit__` for finalization." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T11:59:52.848341Z", "start_time": "2020-10-09T11:59:52.844168Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "<_io.TextIOWrapper name='contact.csv' mode='r' encoding='UTF-8'>\n", "True\n", "True\n" ] } ], "source": [ "with open(\"contact.csv\") as f:\n", " print(f, hasattr(f, \"__enter__\"), hasattr(f, \"__exit__\"), sep=\"\\n\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- `f.__enter__` is called after the file object is successfully created and assigned to `f`, and\n", "- `f.__exit__` is called at the end, which closes the file.\n", "- `f.closed` indicates whether the file is closed." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "ExecuteTime": { "end_time": "2020-09-27T11:53:59.538208Z", "start_time": "2020-09-27T11:53:59.532644Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.closed" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We can iterate a file object in a for loop, \n", "which implicitly call the method `__iter__` to read a file line by line." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:00:38.536083Z", "start_time": "2020-10-09T12:00:38.529215Z" }, "scrolled": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "name, email, phone\n", "Amelia Hawkins,dugorre@lufu.cg,(414) 524-6465\n", "Alta Perez,bos@fiur.sc,(385) 247-9001\n", "Tai Ming Chan,tmchan@cityu.edu.hk,(634) 234-7294\n", "Annie Zimmerman,okodag@saswuf.mn,(259) 862-1082\n", "Eula Crawford,ve@rorohte.mx,(635) 827-9819\n", "Clayton Atkins,vape@nig.eh,(762) 271-7090\n", "Hallie Day,kozzazazi@ozakewje.am,(872) 949-5878\n", "Lida Matthews,joobu@pabnesis.kg,(213) 486-8330\n", "Amelia Pittman,nulif@uposzag.au,(800) 303-3234" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "with open(\"contact.csv\") as f:\n", " for line in f:\n", " print(line, end=\"\")\n", "\n", "hasattr(f, \"__iter__\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Exercise** Print only the first 5 lines of the file `contact.csv`." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "ExecuteTime": { "end_time": "2020-09-28T11:37:13.912284Z", "start_time": "2020-09-28T11:37:13.903693Z" }, "nbgrader": { "grade": false, "grade_id": "read-head", "locked": false, "schema_version": 3, "solution": true, "task": false }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "name, email, phone\n", "Amelia Hawkins,dugorre@lufu.cg,(414) 524-6465\n", "Alta Perez,bos@fiur.sc,(385) 247-9001\n", "Tai Ming Chan,tmchan@cityu.edu.hk,(634) 234-7294\n", "Annie Zimmerman,okodag@saswuf.mn,(259) 862-1082\n", "Eula Crawford,ve@rorohte.mx,(635) 827-9819\n" ] } ], "source": [ "with open(\"contact.csv\") as f:\n", " ### BEGIN SOLUTION\n", " for i, line in enumerate(f):\n", " print(line, end=\"\")\n", " if i >= 5:\n", " break\n", " ### END SOLUTION" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**How to write to a text file?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Consider backing up `contact.csv` to a new file:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:02:09.880084Z", "start_time": "2020-10-09T12:02:09.875981Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "destination = \"private/new_contact.csv\"" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The directory has to be created first if it does not exist:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:03:03.653606Z", "start_time": "2020-10-09T12:03:03.650581Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "import os\n", "\n", "os.makedirs(os.path.dirname(destination), exist_ok=True)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:03:04.900902Z", "start_time": "2020-10-09T12:03:04.766245Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "contact.csv media Objects.ipynb private __pycache__\r\n" ] } ], "source": [ "os.makedirs?\n", "!ls" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "To write to the destination file:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:03:22.588529Z", "start_time": "2020-10-09T12:03:22.581131Z" }, "code_folding": [], "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "with open(\"contact.csv\") as source_file:\n", " with open(destination, \"w\") as destination_file:\n", " destination_file.write(source_file.read())" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:03:46.868953Z", "start_time": "2020-10-09T12:03:46.730249Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "name, email, phone\r\n", "Amelia Hawkins,dugorre@lufu.cg,(414) 524-6465\r\n", "Alta Perez,bos@fiur.sc,(385) 247-9001\r\n", "Tai Ming Chan,tmchan@cityu.edu.hk,(634) 234-7294\r\n", "Annie Zimmerman,okodag@saswuf.mn,(259) 862-1082\r\n", "Eula Crawford,ve@rorohte.mx,(635) 827-9819\r\n", "Clayton Atkins,vape@nig.eh,(762) 271-7090\r\n", "Hallie Day,kozzazazi@ozakewje.am,(872) 949-5878\r\n", "Lida Matthews,joobu@pabnesis.kg,(213) 486-8330\r\n", "Amelia Pittman,nulif@uposzag.au,(800) 303-3234\r\n" ] } ], "source": [ "destination_file.write?\n", "!more {destination}" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- The argument `'w'` for `open` sets the file object to write mode.\n", "- The method `write` writes the input strings to the file." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Exercise** We can also use `a` mode to *append* new content to a file. \n", "Complete the following code to append `new_data` to the file `destination`." ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "ExecuteTime": { "end_time": "2020-09-28T11:40:49.059943Z", "start_time": "2020-09-28T11:40:48.929588Z" }, "nbgrader": { "grade": false, "grade_id": "append", "locked": false, "schema_version": 3, "solution": true, "task": false }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "name, email, phone\n", "Amelia Hawkins,dugorre@lufu.cg,(414) 524-6465\n", "Alta Perez,bos@fiur.sc,(385) 247-9001\n", "Tai Ming Chan,tmchan@cityu.edu.hk,(634) 234-7294\n", "Annie Zimmerman,okodag@saswuf.mn,(259) 862-1082\n", "Eula Crawford,ve@rorohte.mx,(635) 827-9819\n", "Clayton Atkins,vape@nig.eh,(762) 271-7090\n", "Hallie Day,kozzazazi@ozakewje.am,(872) 949-5878\n", "Lida Matthews,joobu@pabnesis.kg,(213) 486-8330\n", "Amelia Pittman,nulif@uposzag.au,(800) 303-3234\n", "Effie, Douglas,galnec@naowdu.tc, (888) 311-9512\n" ] } ], "source": [ "new_data = \"Effie, Douglas,galnec@naowdu.tc, (888) 311-9512\"\n", "with open(destination, \"a\") as f:\n", " ### BEGIN SOLUTION\n", " f.write(\"\\n\")\n", " f.write(new_data)\n", " ### END SOLUTION\n", "!more {destination}" ] }, { "cell_type": "markdown", "metadata": { "ExecuteTime": { "end_time": "2020-07-27T09:38:13.743387Z", "start_time": "2020-07-27T09:38:13.731593Z" }, "slideshow": { "slide_type": "subslide" } }, "source": [ "**How to delete a file?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Note that the file object does not provide any method to delete the file. \n", "Instead, we should use the function `remove` of the `os` module." ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:04:23.600006Z", "start_time": "2020-10-09T12:04:23.593802Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ls: cannot access 'private/new_contact.csv': No such file or directory\n" ] } ], "source": [ "if os.path.exists(destination):\n", " os.remove(destination)\n", "!ls {destination}" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## String Objects" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**How to search for a substring in a string?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "A string object has the method `find` to search for a substring. \n", "E.g., to find the contact information of Tai Ming:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:04:47.021066Z", "start_time": "2020-10-09T12:04:46.994141Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tai Ming Chan,tmchan@cityu.edu.hk,(634) 234-7294\n", "\n" ] } ], "source": [ "str.find?\n", "with open(\"contact.csv\") as f:\n", " for line in f:\n", " if line.find(\"Tai Ming\") != -1:\n", " record = line\n", " print(record)\n", " break" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**How to split and join strings?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "A string can be split according to a delimiter using the `split` method." ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:05:14.298300Z", "start_time": "2020-10-09T12:05:14.291773Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "['Tai Ming Chan', 'tmchan@cityu.edu.hk', '(634) 234-7294\\n']" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "record.split(\",\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The list of substrings can be joined back together using the `join` methods." ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:05:24.735761Z", "start_time": "2020-10-09T12:05:24.732828Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tai Ming Chan\n", "tmchan@cityu.edu.hk\n", "(634) 234-7294\n", "\n" ] } ], "source": [ "print(\"\\n\".join(record.split(\",\")))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Exercise** Print only the phone number (last item) in `record`. Use the method `rstrip` or `strip` to remove unnecessary white spaces at the end." ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:05:53.950678Z", "start_time": "2020-10-09T12:05:53.939647Z" }, "nbgrader": { "grade": false, "grade_id": "strip", "locked": false, "schema_version": 3, "solution": true, "task": false }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(634) 234-7294\n" ] } ], "source": [ "str.rstrip?\n", "### BEGIN SOLUTION\n", "print(record.split(\",\")[-1].rstrip())\n", "### END SOLUTION" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**Exercise** Print only the name (first item) in `record` but with\n", "- surname printed first with all letters in upper case \n", "- followed by a comma, a space, and\n", "- the first name as it is in `record`.\n", "\n", "E.g., `Tai Ming Chan` should be printed as `CHAN, Tai Ming`. \n", "\n", "*Hint*: Use the methods `upper` and `rsplit` (with the parameter `maxsplit=1`)." ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "ExecuteTime": { "end_time": "2020-09-28T11:43:20.143981Z", "start_time": "2020-09-28T11:43:20.136233Z" }, "nbgrader": { "grade": false, "grade_id": "process-name", "locked": false, "schema_version": 3, "solution": true, "task": false }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CHAN, Tai Ming\n" ] } ], "source": [ "str.rsplit?\n", "### BEGIN SOLUTION\n", "first, last = record.split(\",\")[0].rsplit(\" \", maxsplit=1)\n", "print(\"{}, {}\".format(last.upper(), first))\n", "### END SOLUTION" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Operator Overloading" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### What is overloading?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Recall that the addition operation `+` behaves differently for different types." ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:07:04.432674Z", "start_time": "2020-10-09T12:07:04.415150Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 1 + 1 = 2\n", " '1' + '1' = '11'\n" ] }, { "ename": "TypeError", "evalue": "unsupported operand type(s) for +: 'int' and 'str'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_124/530167878.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m \u001b[0;32min\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m\"1\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"1\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"1\"\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[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"{x!r:^5} + {y!r:^5} = {x+y!r}\"\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: unsupported operand type(s) for +: 'int' and 'str'" ] } ], "source": [ "for x, y in (1, 1), (\"1\", \"1\"), (1, \"1\"):\n", " print(f\"{x!r:^5} + {y!r:^5} = {x+y!r}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Having an operator perform differently based on its argument types is called [operator *overloading*](https://en.wikipedia.org/wiki/Operator_overloading).\n", "- `+` is called a *generic* operator.\n", "- We can also have function overloading to create generic functions." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### How to dispatch on type?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The strategy of checking the type for the appropriate implementation is called *dispatching on type*." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "A naive idea is to put all different implementations together:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:07:42.828229Z", "start_time": "2020-10-09T12:07:42.810588Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Do integer summation...\n", " 1 + 1 = 2\n", "Do string concatenation...\n", " '1' + '1' = '11'\n", "Return a TypeError...\n" ] }, { "ename": "TypeError", "evalue": "unsupported operand type(s) for +: 'int' and 'str'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_124/2252612173.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m \u001b[0;32min\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m\"1\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"1\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"1\"\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[0;32m---> 12\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"{x!r:^10} + {y!r:^10} = {add_case_by_case(x,y)!r}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m/tmp/ipykernel_124/2252612173.py\u001b[0m in \u001b[0;36madd_case_by_case\u001b[0;34m(x, y)\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Return a TypeError...\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0my\u001b[0m \u001b[0;31m# replaced by internal implementations\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'str'" ] } ], "source": [ "def add_case_by_case(x, y):\n", " if isinstance(x, int) and isinstance(y, int):\n", " print(\"Do integer summation...\")\n", " elif isinstance(x, str) and isinstance(y, str):\n", " print(\"Do string concatenation...\")\n", " else:\n", " print(\"Return a TypeError...\")\n", " return x + y # replaced by internal implementations\n", "\n", "\n", "for x, y in (1, 1), (\"1\", \"1\"), (1, \"1\"):\n", " print(f\"{x!r:^10} + {y!r:^10} = {add_case_by_case(x,y)!r}\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "It can get quite messy with all possible types and combinations." ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:09:16.114595Z", "start_time": "2020-10-09T12:09:16.107719Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 1 + 1.1 = 2.1\n", " 1 + (1+2j) = (2+2j)\n", " (1, 2) + (1, 2) = (1, 2, 1, 2)\n" ] } ], "source": [ "for x, y in ((1, 1.1), (1, complex(1, 2)), ((1, 2), (1, 2))):\n", " print(f\"{x!r:^10} + {y!r:^10} = {x+y!r}\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**What about new data types?**" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:09:46.300495Z", "start_time": "2020-10-09T12:09:46.290011Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1/2 + 1 = 3/2\n", "1 + 1/2 = 3/2\n" ] } ], "source": [ "from fractions import Fraction # non-built-in type for fractions\n", "\n", "for x, y in ((Fraction(1, 2), 1), (1, Fraction(1, 2))):\n", " print(f\"{x} + {y} = {x+y}\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Weaknesses of the naive approach:\n", "1. New data types require rewriting the addition operation.\n", "1. A programmer may not know all other types and combinations to rewrite the code properly." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### How to have data-directed programming?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The idea is to treat an implementation as a datum that can be returned by the operand types." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- `x + y` is a [*syntactic sugar*](https://en.wikipedia.org/wiki/Syntactic_sugar) that\n", "- invokes the method `type(x).__add__(x,y)` of `type(x)` to do the addition." ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:10:46.316918Z", "start_time": "2020-10-09T12:10:46.313007Z" }, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1/2 + 1 = 3/2\n", "1 + 1/2 = NotImplemented\n" ] } ], "source": [ "for x, y in (Fraction(1, 2), 1), (1, Fraction(1, 2)):\n", " print(f\"{x} + {y} = {type(x).__add__(x,y)}\") # instead of x + y" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- The first case calls `Fraction.__add__`, which provides a way to add `int` to `Fraction`.\n", "- The second case calls `int.__add__`, which cannot provide any way of adding `Fraction` to `int`. (Why not?)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**Why does python return a [`NotImplemented` object](https://docs.python.org/3.6/library/constants.html#NotImplemented) instead of raising an error/exception?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- This allows `+` to continue to handle the addition by\n", "- dispatching on `Fraction` to call its reverse addition method [`__radd__`](https://docs.python.org/3.6/library/numbers.html#implementing-the-arithmetic-operations)." ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:17:26.210151Z", "start_time": "2020-10-09T12:17:26.206468Z" }, "code_folding": [], "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%mytutor -h 500\n", "from fractions import Fraction\n", "\n", "\n", "def add(x, y):\n", " \"\"\"Simulate the + operator.\"\"\"\n", " sum = x.__add__(y)\n", " if sum is NotImplemented:\n", " sum = y.__radd__(x)\n", " return sum\n", "\n", "\n", "for x, y in (Fraction(1, 2), 1), (1, Fraction(1, 2)):\n", " print(f\"{x} + {y} = {add(x,y)}\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The object-oriented programming techniques involved are formally called:\n", "- [*Polymorphism*](https://en.wikipedia.org/wiki/Polymorphism_(computer_science)): Different types can have different implementations of the `__add__` method. \n", "- [*Single dispatch*](https://en.wikipedia.org/wiki/Dynamic_dispatch): The implementation is chosen based on one single type at a time. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Remarks:\n", "- A method with starting and trailing double underscores in its name is called a [*dunder method*](https://dbader.org/blog/meaning-of-underscores-in-python). \n", "- Dunder methods are not intended to be called directly. E.g., we normally use `+` instead of `__add__`.\n", "- [Other operators](https://docs.python.org/3/library/operator.html?highlight=operator) have their corresponding dunder methods that overloads the operator.\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Object Aliasing" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**When are two objects identical?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The keyword `is` checks whether two objects are the same object:" ] }, { "cell_type": "code", "execution_count": 76, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(True, False)" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sum = 1 .__add__(1.0)\n", "sum is NotImplemented, sum is None" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**Is `is` the same as `==`?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "`is` is faster." ] }, { "cell_type": "code", "execution_count": 77, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "41.7 ns ± 1.41 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)\n" ] } ], "source": [ "%%timeit\n", "sum == NotImplemented" ] }, { "cell_type": "code", "execution_count": 78, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "36.2 ns ± 1.78 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)\n" ] } ], "source": [ "%%timeit\n", "sum is NotImplemented" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- `is` checks whether two objects occupy the same memory but \n", "- `==` calls the method `__eq__`." ] }, { "cell_type": "code", "execution_count": 79, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "<>:1: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", "<>:1: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", "<>:1: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", "<>:1: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", "/tmp/ipykernel_3738/3392130193.py:1: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", " 1 is 1, 1 is 1., 1 == 1.\n", "/tmp/ipykernel_3738/3392130193.py:1: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", " 1 is 1, 1 is 1., 1 == 1.\n" ] }, { "data": { "text/plain": [ "(True, False, True)" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 is 1, 1 is 1.0, 1 == 1.0" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "To see this, we can use the function `id` which returns an id number for an object based on its memory location." ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:22:18.902068Z", "start_time": "2020-10-09T12:22:18.885736Z" }, "scrolled": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%mytutor -h 400\n", "x, y = complex(1, 2), complex(1, 2)\n", "z = x\n", "\n", "for expr in (\"id(x)\", \"id(y)\", \"id(z)\", \n", " \"x == y == z\", \"x is y\", \"x is z\"):\n", " print(expr, eval(expr))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "As the box-pointer diagram shows:\n", "- `x` is not `y` because they point to objects at different memory locations, \n", " even though the objects have the same type and value.\n", "- `x` is `z` because the assignment `z = x` binds `z` to the same memory location `x` points to. \n", " `z` is said to be an *alias* (another name) of `x`. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Can we use `is` instead of `==` to compare integers/strings?**" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "ExecuteTime": { "end_time": "2020-10-09T12:22:51.388017Z", "start_time": "2020-10-09T12:22:51.384450Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "<>:1: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", "<>:1: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", "/tmp/ipykernel_124/2596500588.py:1: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", " 10 ** 10 is 10 ** 10, 10 ** 100 is 10 ** 100\n" ] }, { "data": { "text/plain": [ "(True, False)" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "10 ** 10 is 10 ** 10, 10 ** 100 is 10 ** 100" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "<>:3: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", "<>:3: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", "/tmp/ipykernel_124/2881634201.py:3: SyntaxWarning: \"is\" with a literal. Did you mean \"==\"?\n", " x is y, y is \"abc\", x + y is x + \"abc\"\n" ] }, { "data": { "text/plain": [ "(True, True, False)" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = y = \"abc\"\n", "y = \"abc\"\n", "x is y, y is \"abc\", x + y is x + \"abc\"" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The behavior is not entirely predictable because: \n", "- it is possible to avoid storing the same integer/string at different locations by [*interning*](https://www.codesansar.com/python-programming/integer-interning.htm), but\n", "- it is impractical to always avoid it.\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**When should we use `is`?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "`is` can be used for [built-in constants](https://docs.python.org/3/library/constants.html#built-in-constants) such as `None` and `NotImplemented` \n", "because there can only be one instance of each of them." ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.12" }, "latex_envs": { "LaTeX_envs_menu_present": true, "autoclose": false, "autocomplete": true, "bibliofile": "biblio.bib", "cite_by": "apalike", "current_citInitial": 1, "eqLabelWithNumbers": true, "eqNumInitial": 1, "hotkeys": { "equation": "Ctrl-E", "itemize": "Ctrl-I" }, "labels_anchors": false, "latex_user_defs": false, "report_style_numbering": false, "user_envs_cfg": false }, "rise": { "enable_chalkboard": true, "scroll": true, "theme": "white" }, "toc": { "base_numbering": 1, "nav_menu": { "height": "195px", "width": "330px" }, "number_sections": true, "sideBar": true, "skip_h1_title": true, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": { "height": "582.599px", "left": "657.989px", "top": "287px", "width": "182.844px" }, "toc_section_display": true, "toc_window_display": false }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }