{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Advanced Techniques in Python: Classes, Objects, Functions, Memory\n", "This tutorial includes some advanced topics and techniques frequently used in Python.\n", "The topics covered in this part are:\n", "\n", "- Classes, objects, and methods. OOP in Python.\n", "- Advanced techneques in objects and functions manipulation.\n", "- Modules and their structure. How to develop a Python module.\n", "- Python memory management.\n", "- The Pythonic way: Tips & Tricks.\n", "\n", "**Prerequisites:** *Basic and Intermediate ACM Python tutorials or some experience in Pyhton and programming in general.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Object-oriented programming in Python\n", "Python is a lexible language. You can use it in three ways: procedural programming, object-oriented programming, functional programming. Even though you are using one of the approaches (*you might think!*), behind the scene it anyway manipulates objects... Why?" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print type(1)\n", "print type(int)\n", "\n", "def f(): pass\n", "print type(f)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\n", "\n", "\n" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.1. How to create classes and build class hierarchies?\n", "Let's create an example class `Person` and add a couple of fields and methods to it." ] }, { "cell_type": "code", "collapsed": true, "input": [ "class Person(object):\n", " def __init__(self, name):\n", " self.name = name\n", " \n", " def WhatIsYourName(self):\n", " return self.name\n", "\n", "p1 = Person('John')\n", "p1.WhatIsYourName()" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's create a small hierarchy of classes with a base class `Person`." ] }, { "cell_type": "code", "collapsed": false, "input": [ "class Employee(Person):\n", " def __init__(self, name, organization):\n", " self.name = name\n", " self.employer = organization\n", " \n", " def WhereDoYouWork(self):\n", " return self.employer\n", "\n", "p2 = Employee('Joshua', 'KAUST')\n", "print '%s works at %s' % (p2.WhatIsYourName(), p2.WhereDoYouWork())" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "class PhD(Employee):\n", " title = 'PhD' # this will be a class-wise field!\n", " \n", " def __init__(self, name, organization, major):\n", " super(PhD, self).__init__(name, organization) # or you can write Employee.__init__(self, name, organization)\n", " self.major = major\n", " \n", " def WhatIsYourMajor(self):\n", " return self.major\n", "\n", "p3 = PhD('Chris','KAUST','EE')\n", "print '%s is a %s in %s at %s' % (p3.name, p3.title, p3.WhatIsYourMajor(), p3.employer)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Exercise:\n", "\n", "- Create a class `Student` that has `Person` as a base class.\n", "- Make `Student` have fields `major` and `school`. `school` should be an optional field with `None` as the default value.\n", "- Add a method `WhereDoYouStudy` to `Student` class.\n", "- Make `PhD` class have two base classes - `Employee` and `Student`.\n", "- Add `WhereDoYouWork` function to `PhD` (it will shadow `Employee`'s `WhereDoYouWork`) the following way: if `school` is not defined for a `PhD`, i.e., is equal to `None`, then return the result `Employee`'s `WhereDoYouWork` returns, otherwise return Student's `WhereDoYouStudy` output.\n", "\n", "You can extend the above cells or use the below cell for your code." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "#%load solutions/oop_ex.py" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.2. Extending existing Python types\n", "Often, it is very useful to extend existing types and classes when an additional feature is needed. For this section, let's try to extend `dict` into a class `Graph`. But before this let's have a closer look at how the basic types/classes in python are organized." ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Check the type of class dict\n", "type(dict)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# List all the methods, fields and properties dict class has\n", "dir(dict)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# An example of 'magic' method with two underscores\n", "dict.__getitem__?" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**NOTE:** A well written and more detailed guide on so called Python \"magic methods\" (with double underscores) you can find [here](http://www.rafekettler.com/magicmethods.html)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, knowing that `dict` is basically a class, we can build another class `Graph` and use dict as the base class. Our `Graph` will have the following structure: each key-element will be a node, each value element will be a `list` of the adjacent nodes. Graph will be initialized with a list of edges." ] }, { "cell_type": "code", "collapsed": false, "input": [ "class Graph(dict):\n", " \"\"\"Graph class, extends dict\"\"\"\n", " def __init__(self, edges):\n", " \"\"\"Initialize graph with a list of 2-tuples. Each tuple is a directed edge.\"\"\"\n", " for u, v in edges:\n", " try:\n", " self[u].append(v)\n", " except KeyError, e:\n", " self[u] = [v]\n", " # instead of try-except you can use: self[u] = self.get(u,[]) + [v]\n", " \n", " def __str__(self):\n", " \"\"\"Returns a Graph representation. Called by 'print' for any object we would like to print.\"\"\"\n", " representation = '\\n'.join([\"%i -> [%s]\" % (u, ','.join([str(v) for v in V]))\n", " for u, V in self.iteritems()])\n", " return representation\n", " " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "g = Graph([(1,2), (2,3), (1,3)])\n", "print g" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Exercise:\n", "Build an extention for dict called \"SortedDict\". Whenever you print an instance of such `dict`, print it sorted by keys in the ascending order. For the test please use the `dict` below." ] }, { "cell_type": "code", "collapsed": false, "input": [ "d = {100: \"Hi\", 7:\"Week\", 24:\"Work\", 2009:\"KAUST\"}\n", "print d" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "#%load solutions/sorted_dict.py" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.3. Functions are also classes, and we can play with them the same way!\n", "As we mentioned, everything in Python is an object. Even a function. Let's check it out and see how we can exploit this." ] }, { "cell_type": "code", "collapsed": false, "input": [ "dir(len)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# Check the help for the __call__ method\n", "len.__call__?" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, since functions are objects, we can use them as objects, e.g., as another funciton arguments. Consider the following example." ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Apply function example\n", "def apply(data, func):\n", " \"\"\"Loop through the data and apply the provided function.\"\"\"\n", " return [func(d) for d in data]\n", "\n", "apply([1, -1, 2, 10, 100, -404], str)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# Bind function example\n", "def bind(func, **kwargs):\n", " def bfunc(*args):\n", " return func(*args, **kwargs)\n", " return bfunc" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a quick example, let's make function `sorted` sort the provided iterable object in the reverse order." ] }, { "cell_type": "code", "collapsed": false, "input": [ "sorted([1, -1, 2, 10, 100, -404])" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "sorted?" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "rev_sorted = bind(sorted, reverse=True)\n", "rev_sorted([1, -1, 2, 10, 100, -404])" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The last pattern when we have a function generates a function based on the provided one is unltimately frequent and very useful. Let's consider an example, and firts write a simple Fibonacci sequence generator function.\n", "\n", "*(FYI: Fibonacci recurrent numerical sequence is defined as follows: F(n) = F(n-1) + F(n-2), F(0) = 0, F(1) = 1)*" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def Fib(n):\n", " \"\"\"Return the n-th Fibonacci number.\"\"\"\n", " assert type(n) is int and n >= 0, \"ERROR (Fib): index should be positive and integer!\"\n", " return Fib(n-1) + Fib(n-2) if n > 1 else 1 if n is 1 else 0" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "[Fib(i) for i in range(15)]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fibonacci function is recurrent. Moreover, for every input n, it should compute values for all the previous indices. Is this efficient? Of course not. Let's make it more efficient, hacking the \\_\\_call\\_\\_ method and adding some caching. We will make it using decorators." ] }, { "cell_type": "code", "collapsed": false, "input": [ "import collections\n", "\n", "def memoize(func):\n", " \"\"\"A caching decorator. Checks and returns a cached value before applying the function itself.\"\"\"\n", " cache = {}\n", " def cachedFunc(*args):\n", " if args not in cache:\n", " print \"Cache miss!\"\n", " cache[args] = func(*args)\n", " return cache[args]\n", " return cachedFunc\n", "\n", "@memoize\n", "def Fib(n):\n", " \"\"\"Return the n-th Fibonacci number.\"\"\"\n", " assert type(n) is int and n >= 0, \"ERROR (Fib): index should be positive and integer!\"\n", " return Fib(n-1) + Fib(n-2) if n > 1 else 1 if n is 1 else 0" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "[Fib(i) for i in range(16)]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Exercise:\n", "Implement a decorator that will trace Fibonacci function calls. Whenever the Fib function called, print it and its arguments. If it is called recurrently, maintain the indent: each subsequent recurrent call should be indented with two more spaces." ] }, { "cell_type": "code", "collapsed": false, "input": [ "#%load solutions/fib_trace.py" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**NOTE:** You can find a lot of useful decorators along with their design patterns in [this library](https://wiki.python.org/moin/PythonDecoratorLibrary)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. What are modules in Python? How to develop your own?\n", "If you used Python even for a bit, you most probably noticed that the real power of the language is in its modules and packages which you can import into your script and use the code you or somebody else developed and tested before. But how to write your own package? Right, it is simple... because modules are also objects!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The simplest way is just create a file, say `MyModule.py`, put some functions and classes you implemented in it, and finally write" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import MyModule" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or something like" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from MyModule import * # or from MyModule import (MyFunctionName, MyClassName)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, if you would like to build something BIG, say a whole package for sound processing, you would probably prefer not putting everything in a mess into a single file, but rather you would prefer splitting everything logically into separate files or even folders. Then, your structure should look like this: (*Example is taken from the Python [documentation page](http://docs.python.org/2/tutorial/modules.html#packages)*)" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "sound/ Top-level package\n", " __init__.py Initialize the sound package\n", " formats/ Subpackage for file format conversions\n", " __init__.py\n", " wavread.py\n", " wavwrite.py\n", " aiffread.py\n", " aiffwrite.py\n", " auread.py\n", " auwrite.py\n", " ...\n", " effects/ Subpackage for sound effects\n", " __init__.py\n", " echo.py\n", " surround.py\n", " reverse.py\n", " ...\n", " filters/ Subpackage for filters\n", " __init__.py\n", " equalizer.py\n", " vocoder.py\n", " karaoke.py\n", " ..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note the `__init__.py` files. They might be just empty (in most of the packages they are), but if you need to do some additional stuff at the moment of importing module (say, you want to print your module's version information and a license), you should do this exactly in the appropriate `__init__.py`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Also note the subfolders you might have with submodules. Large packages with large libraries use exactly this kind of structure which allows programmers import only the submodules they are interested in working with. Example:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import sound.effects.echo as echo" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's have a look at a more concrete example (*taken from [Johansson's Python lectures](https://github.com/jrjohansson/scientific-python-lectures)*)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%file mymodule.py\n", "\"\"\"\n", "Example of a python module. Contains a variable called my_variable,\n", "a function called my_function, and a class called MyClass.\n", "\"\"\"\n", "\n", "my_variable = 0\n", "\n", "def my_function():\n", " \"\"\"\n", " Example function\n", " \"\"\"\n", " return my_variable\n", " \n", "class MyClass:\n", " \"\"\"\n", " Example class.\n", " \"\"\"\n", "\n", " def __init__(self):\n", " self.variable = my_variable\n", " \n", " def set_variable(self, new_value):\n", " \"\"\"\n", " Set self.variable to a new value\n", " \"\"\"\n", " self.variable = new_value\n", " \n", " def get_variable(self):\n", " return self.variable" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "import mymodule" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "help(mymodule)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "mymodule.my_variable" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "mymodule.my_function" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "my_class = mymodule.MyClass() \n", "my_class.set_variable(10)\n", "my_class.get_variable()" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. Memory management in Python\n", "In this section we shed some light on how the memory is actually managed by Python, show you important-to-know techniques that will help you build efficient code and avoid common mistakes." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.1. Size of objects in Python\n", "First, we should get a good feeling of what the actual sizes of objects in Pyhton are, and how the sizes grow whenever we create lists/dictionaries/tuples out of some number of objects." ] }, { "cell_type": "code", "collapsed": false, "input": [ "# The function for showing size of objects (source: http://deeplearning.net/software/theano/tutorial/python-memory-management.html)\n", "import sys\n", "\n", "def show_sizeof(x, level=0):\n", " print \"\\t\" * level, x.__class__, sys.getsizeof(x), x\n", " if hasattr(x, '__iter__'):\n", " if hasattr(x, 'items'):\n", " for xx in x.items():\n", " show_sizeof(xx, level + 1)\n", " else:\n", " for xx in x:\n", " show_sizeof(xx, level + 1)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "sys.getsizeof?" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# Lets check sizes of different objects (sizes are indicated for 64-bit Python)\n", "show_sizeof(None) # 16 bytes for None\n", "show_sizeof(1) # 24 bytes for 64-bit int - 3 time the size of int64_t in C\n", "show_sizeof(2**500) # 92 bytes for 64-bit Python's long with unconstrained length\n", "\n", "show_sizeof(0.5) # 24 bytes for 64-bit double\n", "show_sizeof(\"\") # 37 bytes for empty string\n", "show_sizeof(u\"\") # 50 for empty unicode string\n", "show_sizeof(\"Test\") # 41 for not empty string (+1 byte per character)\n", "show_sizeof(u\"Test\") # 58 for not empty unicode string (+2 bytes per character)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python lists are actually [dynamic arrays](http://en.wikipedia.org/wiki/Dynamic_array)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "show_sizeof([]) # 72 bytes\n", "show_sizeof([1, \"test\", 0.5]) # 96 bytes. The capacity of this list is 6; +4 bytes per each link in a list." ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All of these details seem to be minor, unless you start building large-scale applications, or process huge amounts of data for your projects. So, keep this in mind." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.2. Python internal memory management\n", "Here we just briefly discuss a pretty wasteful approach to manage memory allocation employed in Python. For thorough description and possible solutions you can refer to http://www.evanjones.ca/memoryallocator/." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can run a small experiment using [memory profiler](https://github.com/fabianp/memory_profiler) utitlity." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%file memory-profile-me.py\n", "\n", "import copy\n", "import memory_profiler\n", "\n", "@profile\n", "def function():\n", " x = range(1000000) # allocate a big list\n", " y = copy.deepcopy(x)\n", " del x\n", " return y\n", "\n", "if __name__==\"__main__\":\n", " function()" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "%run -m memory_profiler memory-profile-me.py" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Filename: memory-profile-me.py\n", "\n", "Line # Mem usage Increment Line Contents\n", "================================================\n", " 5 15.883 MiB 0.000 MiB @profile\n", " 6 def function():\n", " 7 46.945 MiB 31.062 MiB x = range(1000000) # allocate a big list\n", " 8 149.242 MiB 102.297 MiB y = copy.deepcopy(x)\n", " 9 149.242 MiB 0.000 MiB del x\n", " 10 149.242 MiB 0.000 MiB return y\n", "\n", "\n" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, what does this chart above tell us? Somewhy, Python didn't shrink the memory in use after we deleted `x`. What happened?\n", "\n", "To speed up memory allocation, Python reuses already allocated chuncks. It keeps several lists for small objects (separate lists for different sizes). Whenever we create a new object, Python either allocates a new block, or reuses a free one from one of the lists. That's why when we deleted x, the memory usage didn't shrink." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4. The Pythonic way: Tips & Tricks\n", "Python is a nice language. If you had known other programming languages before starting using Python, you can easily switch to Python (learn it literaly in 3-6 hours), and continue writing ~~ugly awkward~~ code using idioms and structures from your previous languages. However, Python is beautiful, very succinct and very expressive. This section is devoted to show you some essential well known (or less known) Python idioms (or tricks, if you will) that can make your code shorter and more elegant." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### List comprehensions (the same for dicts, sets, frozensets, and actually all iterable objects)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Basic for-loop comprehension\n", "a = [1,2,3,4,5,6,7]\n", "b = [x**2 for x in a]\n", "print b" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# For-loop if-else comprehension\n", "c = [x**2 for x in a if x > 4]\n", "print c" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# Multiple for-loop if-else comprehension\n", "llist = [[1,2,3],(4,5,6),(7,8,9)]\n", "c = [x**2 for sublist in llist for x in sublist if x % 2 == 0]\n", "print c" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Infinite structures" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# In Python you can actually use infinite lsits and dicts (without running out of memory!)\n", "a = [1,2,3]\n", "a.append(a)\n", "print a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a[3][3][3][3][3]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Other fancy stuff" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Quick swap\n", "a = 1\n", "b = 2\n", "print a,b\n", "a, b = b, a\n", "print a, b" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# Nice math-like comparison notation\n", "x = 5\n", "print 3 < x < 8\n", "print x < 10 < 5*x < 99\n", "print 2 > x < 7" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# List flattening techniques\n", "a = [[1,2,3],[4,5,6],[7,8,9]]\n", "print sum(a,[]) # this works only with nested lists (or objects with __add__ method defined)\n", "print [x for b in a for x in b] # works with any nested iterables" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# Pairing elements of two lists\n", "first, second = [1,2,3,4,5], [6,7,8,9,10]\n", "print first\n", "print second\n", "\n", "paired = zip(first,second)\n", "print paired" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# Unpairing the elements back into two lists (NOTE: Lists turn into tuples. This is due to zip implementation.)\n", "a, b = zip(*paired)\n", "print a\n", "print b" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# Providing function arguments via structures\n", "def func(a, b, c, kw1 = '', kw2 = 0):\n", " print a\n", " print b\n", " print c\n", " print kw1\n", " print kw2\n", "\n", "args = (1, 2, 3)\n", "kwargs = {'kw1':'Hello', 'kw2':100}\n", "func(*args,**kwargs)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# Enumeration of the elements\n", "l = [\"spam\", \"ham\", \"eggs\"]\n", "print list(enumerate(l))\n", "print list(enumerate(l,5))" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Copyright 2014, Maruan Al-Shedivat, ACM Student Member.*" ] } ], "metadata": {} } ] }