Created
June 25, 2015 17:34
-
-
Save aganders3/1b725f134873bbf71611 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "# Mutable vs. Immutable Objects \n<br />\n### DesertPy Lightning Talk, June 2015\n<br />\n### Ashley Anderson\n[@aganders3](twitter.com/aganders3) on Twitter or [email protected]" | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "## Everything is an object" | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "-" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "Every Python object has a type, identity, and *value*.\n\nThe builtin function `type()` returns a `type` object. \nThe builtin function `id()` returns the object's identity (an integer). \nValue is kind of vague, though." | |
}, | |
{ | |
"metadata": { | |
"scrolled": true, | |
"collapsed": false, | |
"slideshow": { | |
"slide_type": "-" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "print 1, type(1), id(1)\n\nfoo = range(10)\nprint foo, type(foo), id(foo)\n\nimport sys \nprint sys, type(sys), id(sys)\n\ndef bar():\n pass\n\nprint bar, type(bar), id(bar)", | |
"execution_count": 169, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": "1 <type 'int'> 4299197592\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] <type 'list'> 4415085312\n<module 'sys' (built-in)> <type 'module'> 4297509808\n<function bar at 0x10728b320> <type 'function'> 4415075104\n" | |
} | |
] | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "## Mutability is about *values*\n\nThink of an object's value as any and all of its attributes. For example, anything you'd type `self.` to get at from inside if you wrote the class yourself.\n\nMost custom classes are mutable. To create a simple immutable class, try using a [`namedtuple`](https://docs.python.org/2/library/collections.html#collections.namedtuple). Otherwise you can raise a `TypeError` from `__setattr__` to make your own immutable type." | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "subslide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "### Immutable objects\nYou can't change their values. \nThe value of `x` is the same before and after `foo` is called.\n\n x = some_immutable\n foo(x)\n print x\n\nThis is *kind of* like pass-by-value.\n\nImmutable objects include **numbers**, **strings**, **tuples**." | |
}, | |
{ | |
"metadata": { | |
"collapsed": false, | |
"slideshow": { | |
"slide_type": "fragment" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "def add_one(bar):\n bar += 1\n\nb = 5\nprint b, id(b)\nadd_one(b)\nprint b, id(b)", | |
"execution_count": 120, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": "5 4299197496\n5 4299197496\n" | |
} | |
] | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "subslide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "### Mutable objects\nYou can change their values. \nThe value of `y` *may be different* after `foo` is called.\n\n y = some_mutable\n foo(y)\n print y\n \nThis is *kind of* like pass-by-reference.\n\nMutable objects include **lists**, **dictionaries**, etc." | |
}, | |
{ | |
"metadata": { | |
"collapsed": false, | |
"slideshow": { | |
"slide_type": "fragment" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "def reverse_list(foo):\n foo.reverse()\n\na = range(10)\nprint a, id(a)\nreverse_list(a)\nprint a, id(a)", | |
"execution_count": 121, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 4415096664\n[9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 4415096664\n" | |
} | |
] | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "## But, wait...\nIt's pretty easy to change the value of a number variable..." | |
}, | |
{ | |
"metadata": { | |
"collapsed": false, | |
"slideshow": { | |
"slide_type": "fragment" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "foo = 42\nprint foo\n\nfoo += 1\nprint foo\n\nfoo = 42\nprint foo", | |
"execution_count": 151, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": "42\n43\n42\n" | |
} | |
] | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "subslide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "## Nah...\nThe assignment operator doesn't change the value of an object, it changes its identity." | |
}, | |
{ | |
"metadata": { | |
"collapsed": false, | |
"slideshow": { | |
"slide_type": "-" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "foo = 42\nprint foo, id(foo)\nfoo += 1\nprint foo, id(foo)\nfoo = \"bar\"\nprint foo, id(foo)", | |
"execution_count": 148, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": "42 4299198584\n43 4299198560\nbar 4381029040\n" | |
} | |
] | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "## Values get confusing when we have containers\n\nIf you have an immutable container (e.g. a tuple) that holds mutable objects (e.g. lists), you can still mutate the contained objects without mutating the container." | |
}, | |
{ | |
"metadata": { | |
"collapsed": false, | |
"slideshow": { | |
"slide_type": "-" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "A = ([],[],[])\nprint A, id(A[0]), id(A)\nA[0].append(5)\nprint A, id(A[0]), id(A)\nA[1] = [5]", | |
"execution_count": 171, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": "([], [], []) 4414903504 4414893984\n([5], [], []) 4414903504 4414893984\n" | |
}, | |
{ | |
"ename": "TypeError", | |
"evalue": "'tuple' object does not support item assignment", | |
"traceback": [ | |
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", | |
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", | |
"\u001b[0;32m<ipython-input-171-868c79a8f9fc>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mA\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mA\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mA\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mA\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mA\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;36m5\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", | |
"\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" | |
], | |
"output_type": "error" | |
} | |
] | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "## Gotcha!\nMostly you don't have to think about this stuff, but sometimes you do." | |
}, | |
{ | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "def my_appending_function(element, initial_list=[]):\n # do some stuff\n initial_list.append(element)\n return initial_list", | |
"execution_count": 1, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"collapsed": false, | |
"slideshow": { | |
"slide_type": "fragment" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "print my_appending_function((1,2,3,5), range(2))\nprint my_appending_function(10)\nprint my_appending_function(5)", | |
"execution_count": 2, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": "[0, 1, (1, 2, 3, 5)]\n[10]\n[10, 5]\n" | |
} | |
] | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "subslide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "## Mutable objects as default arguments\nThese are defined *once* when the function is defined. This is a result of [`def` being an *executable statement* that binds the name of the function to the function object](http://effbot.org/zone/default-values.htm). All this has something to do with Python functions being \"first class\" objects." | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "subslide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "## Mutable objects as deafault arguments\nSo...instead of this:" | |
}, | |
{ | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "-" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "def my_appending_function(element, initial_list=[]):\n # do some stuff\n initial_list.append(element)\n return initial_list", | |
"execution_count": 165, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "Do this:" | |
}, | |
{ | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "-" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "def my_appending_function(element, initial_list=None):\n if initial_list is None:\n initial_list = []\n # do some stuff\n initial_list.append(element)\n return initial_list", | |
"execution_count": 166, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"slideshow": { | |
"slide_type": "subslide" | |
} | |
}, | |
"cell_type": "markdown", | |
"source": "## Mutable objects as default arguments\n\nNow it does what you (may have) expected:" | |
}, | |
{ | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "def my_appending_function(number, initial_list=None):\n if initial_list is None:\n initial_list = []\n # do some stuff\n initial_list.append(number)\n return initial_list", | |
"execution_count": 77, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"collapsed": false, | |
"slideshow": { | |
"slide_type": "fragment" | |
}, | |
"trusted": true | |
}, | |
"cell_type": "code", | |
"source": "print my_appending_function(10)\nprint my_appending_function(5)\nprint my_appending_function(10)\nprint my_appending_function(5)", | |
"execution_count": 167, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": "[10]\n[5]\n[10]\n[5]\n" | |
} | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"name": "python2", | |
"display_name": "Python 2", | |
"language": "python" | |
}, | |
"language_info": { | |
"mimetype": "text/x-python", | |
"nbconvert_exporter": "python", | |
"name": "python", | |
"pygments_lexer": "ipython2", | |
"version": "2.7.10", | |
"file_extension": ".py", | |
"codemirror_mode": { | |
"version": 2, | |
"name": "ipython" | |
} | |
}, | |
"celltoolbar": "Slideshow" | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 0 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment