Skip to content

Instantly share code, notes, and snippets.

@minrk
Last active April 8, 2024 17:14
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save minrk/6011986 to your computer and use it in GitHub Desktop.
Save minrk/6011986 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"metadata": {},
"cell_type": "markdown",
"source": "# Importing IPython Notebooks as Modules"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "It is a common problem that people want to import code from IPython Notebooks.\nThis is made difficult by the fact that Notebooks are not plain Python files,\nand thus cannot be imported by the regular Python machinery.\n\nThere is a flag in the notebook server that provides a certain workaround for a small set of cases,\nbut I think it's gross so I won't even discuss it.\n\nFortunately, Python provides some fairly sophisticated [hooks](http://www.python.org/dev/peps/pep-0302/) into the import machinery,\nso we can actually make IPython notebooks importable without much difficulty,\nand only using public APIs.\n\nForgive me if some of this is gross or wrong,\nI haven't really written import hooks before."
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "import io, os, sys, types",
"execution_count": 1,
"outputs": []
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "from IPython.nbformat import current\nfrom IPython.core.interactiveshell import InteractiveShell",
"execution_count": 2,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Import hooks typically take the form of two objects:\n\n1. a module **loader**, which takes a module name (e.g. `'IPython.display'`), and returns a Module\n2. a module **finder**, which figures out whether a module might exist, and tells Python what **loader** to use"
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "def find_notebook(fullname, path=None):\n \"\"\"find a notebook, given its fully qualified name and an optional path\"\"\"\n name = fullname.rsplit('.', 1)[-1]\n if not path:\n path = ['']\n for d in path:\n nb_path = os.path.join(d, name + \".ipynb\")\n if os.path.isfile(nb_path):\n return nb_path\n ",
"execution_count": 3,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Notebook Loader"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Here we have our Notebook Loader.\nIt's actually quite simple - once we figure out the filename of the module,\nall it does is:\n\n1. load the notebook document into memory\n2. create an empty Module\n3. execute every cell in the Module namespace\n\nSince IPython cells can have extended syntax,\nthe IPython transform is applied to turn each of these cells into their pure-Python counterparts before executing them.\nIf all of your notebook cells are pure-Python,\nthis step is unnecessary."
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "class NotebookLoader(object):\n \"\"\"Module Loader for IPython Notebooks\"\"\"\n def __init__(self, path=None):\n self.shell = InteractiveShell.instance()\n self.path = path\n \n def load_module(self, fullname):\n \"\"\"import a notebook as a module\"\"\"\n path = find_notebook(fullname, self.path)\n \n print (\"importing IPython notebook from %s\" % path)\n \n # load the notebook object\n with io.open(path, 'r', encoding='utf-8') as f:\n nb = current.read(f, 'json')\n \n \n # create the module and add it to sys.modules\n # if name in sys.modules:\n # return sys.modules[name]\n mod = types.ModuleType(fullname)\n mod.__file__ = path\n mod.__loader__ = self\n sys.modules[fullname] = mod\n \n # extra work to ensure that magics that would affect the user_ns\n # actually affect the notebook module's ns\n save_user_ns = self.shell.user_ns\n self.shell.user_ns = mod.__dict__\n \n try:\n for cell in nb.worksheets[0].cells:\n if cell.cell_type == 'code' and cell.language == 'python':\n # transform the input to executable Python\n code = self.shell.input_transformer_manager.transform_cell(cell.input)\n # run the code in themodule\n exec code in mod.__dict__\n finally:\n self.shell.user_ns = save_user_ns\n return mod\n",
"execution_count": 4,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## The Module Finder"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "The finder is a simple object that tells you whether a name can be imported,\nand returns the appropriate loader.\nAll this one does is check, when you do:\n\n```python\nimport mynotebook\n```\n\nit checks whether `mynotebook.ipynb` exists.\nIf a notebook is found, then it returns a NotebookLoader.\n\nAny extra logic is just for resolving paths within packages."
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "class NotebookFinder(object):\n \"\"\"Module finder that locates IPython Notebooks\"\"\"\n def __init__(self):\n self.loaders = {}\n \n def find_module(self, fullname, path=None):\n nb_path = find_notebook(fullname, path)\n if not nb_path:\n return\n \n key = path\n if path:\n # lists aren't hashable\n key = os.path.sep.join(path)\n \n if key not in self.loaders:\n self.loaders[key] = NotebookLoader(path)\n return self.loaders[key]\n",
"execution_count": 5,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Register the hook"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Now we register the `NotebookFinder` with `sys.meta_path`"
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "sys.meta_path.append(NotebookFinder())",
"execution_count": 6,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "After this point, my notebooks should be importable.\n\nLet's look at what we have in the CWD:"
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "ls",
"execution_count": 7,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": "Importing Notebooks.ipynb bs.ipynb mynotebook.ipynb \u001b[34mnb\u001b[m\u001b[m/\r\n"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "So I should be able to `import mynotebook`.\n"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### Aside: displaying notebooks"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Here is some simple code to display the contents of a notebook\nwith syntax highlighting, etc."
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "from pygments import highlight\nfrom pygments.lexers import PythonLexer\nfrom pygments.formatters import HtmlFormatter\n\nfrom IPython.display import display, HTML\n\nformatter = HtmlFormatter()\nlexer = PythonLexer()\n\n# publish the CSS for pygments highlighting\ndisplay(HTML(\"\"\"\n<style type='text/css'>\n%s\n</style>\n\"\"\" % formatter.get_style_defs()\n))",
"execution_count": 8,
"outputs": [
{
"metadata": {},
"data": {
"text/plain": "<IPython.core.display.HTML at 0x1051976d0>",
"text/html": "\n<style type='text/css'>\n.hll { background-color: #ffffcc }\n.c { color: #408080; font-style: italic } /* Comment */\n.err { border: 1px solid #FF0000 } /* Error */\n.k { color: #008000; font-weight: bold } /* Keyword */\n.o { color: #666666 } /* Operator */\n.cm { color: #408080; font-style: italic } /* Comment.Multiline */\n.cp { color: #BC7A00 } /* Comment.Preproc */\n.c1 { color: #408080; font-style: italic } /* Comment.Single */\n.cs { color: #408080; font-style: italic } /* Comment.Special */\n.gd { color: #A00000 } /* Generic.Deleted */\n.ge { font-style: italic } /* Generic.Emph */\n.gr { color: #FF0000 } /* Generic.Error */\n.gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.gi { color: #00A000 } /* Generic.Inserted */\n.go { color: #888888 } /* Generic.Output */\n.gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.gs { font-weight: bold } /* Generic.Strong */\n.gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.gt { color: #0044DD } /* Generic.Traceback */\n.kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n.kp { color: #008000 } /* Keyword.Pseudo */\n.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n.kt { color: #B00040 } /* Keyword.Type */\n.m { color: #666666 } /* Literal.Number */\n.s { color: #BA2121 } /* Literal.String */\n.na { color: #7D9029 } /* Name.Attribute */\n.nb { color: #008000 } /* Name.Builtin */\n.nc { color: #0000FF; font-weight: bold } /* Name.Class */\n.no { color: #880000 } /* Name.Constant */\n.nd { color: #AA22FF } /* Name.Decorator */\n.ni { color: #999999; font-weight: bold } /* Name.Entity */\n.ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n.nf { color: #0000FF } /* Name.Function */\n.nl { color: #A0A000 } /* Name.Label */\n.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n.nt { color: #008000; font-weight: bold } /* Name.Tag */\n.nv { color: #19177C } /* Name.Variable */\n.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n.w { color: #bbbbbb } /* Text.Whitespace */\n.mf { color: #666666 } /* Literal.Number.Float */\n.mh { color: #666666 } /* Literal.Number.Hex */\n.mi { color: #666666 } /* Literal.Number.Integer */\n.mo { color: #666666 } /* Literal.Number.Oct */\n.sb { color: #BA2121 } /* Literal.String.Backtick */\n.sc { color: #BA2121 } /* Literal.String.Char */\n.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n.s2 { color: #BA2121 } /* Literal.String.Double */\n.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n.sh { color: #BA2121 } /* Literal.String.Heredoc */\n.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n.sx { color: #008000 } /* Literal.String.Other */\n.sr { color: #BB6688 } /* Literal.String.Regex */\n.s1 { color: #BA2121 } /* Literal.String.Single */\n.ss { color: #19177C } /* Literal.String.Symbol */\n.bp { color: #008000 } /* Name.Builtin.Pseudo */\n.vc { color: #19177C } /* Name.Variable.Class */\n.vg { color: #19177C } /* Name.Variable.Global */\n.vi { color: #19177C } /* Name.Variable.Instance */\n.il { color: #666666 } /* Literal.Number.Integer.Long */\n</style>\n"
},
"output_type": "display_data"
}
]
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "def show_notebook(fname):\n \"\"\"display a short summary of the cells of a notebook\"\"\"\n with io.open(fname, 'r', encoding='utf-8') as f:\n nb = current.read(f, 'json')\n html = []\n for cell in nb.worksheets[0].cells:\n html.append(\"<h4>%s cell</h4>\" % cell.cell_type)\n if cell.cell_type == 'code':\n html.append(highlight(cell.input, lexer, formatter))\n else:\n html.append(\"<pre>%s</pre>\" % cell.source)\n display(HTML('\\n'.join(html)))\n\nshow_notebook(\"mynotebook.ipynb\")",
"execution_count": 9,
"outputs": [
{
"metadata": {},
"data": {
"text/plain": "<IPython.core.display.HTML at 0x105200550>",
"text/html": "<h4>heading cell</h4>\n<pre>My Notebook</pre>\n<h4>code cell</h4>\n<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">foo</span><span class=\"p\">():</span>\n <span class=\"k\">return</span> <span class=\"s\">&quot;foo&quot;</span>\n</pre></div>\n\n<h4>code cell</h4>\n<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">has_ip_syntax</span><span class=\"p\">():</span>\n <span class=\"n\">listing</span> <span class=\"o\">=</span> <span class=\"err\">!</span><span class=\"n\">ls</span>\n <span class=\"k\">return</span> <span class=\"n\">listing</span>\n</pre></div>\n\n<h4>code cell</h4>\n<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">whatsmyname</span><span class=\"p\">():</span>\n <span class=\"k\">return</span> <span class=\"n\">__name__</span>\n</pre></div>\n"
},
"output_type": "display_data"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "So my notebook has a heading cell and some code cells,\none of which contains some IPython syntax.\n\nLet's see what happens when we import it"
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "import mynotebook",
"execution_count": 10,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": "importing IPython notebook from mynotebook.ipynb\n"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Hooray, it imported! Does it work?"
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "mynotebook.foo()",
"execution_count": 11,
"outputs": [
{
"metadata": {},
"data": {
"text/plain": "'foo'"
},
"output_type": "execute_result",
"execution_count": 11
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Hooray again!\n\nEven the function that contains IPython syntax works:"
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "mynotebook.has_ip_syntax()",
"execution_count": 12,
"outputs": [
{
"metadata": {},
"data": {
"text/plain": "['Importing Notebooks.ipynb', 'bs.ipynb', 'mynotebook.ipynb', 'nb']"
},
"output_type": "execute_result",
"execution_count": 12
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Notebooks in packages"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "We also have a notebook inside the `nb` package,\nso let's make sure that works as well."
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "ls nb",
"execution_count": 13,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": "__init__.py __init__.pyc other.ipynb\r\n"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Note that the `__init__.py` is necessary for `nb` to be considered a package,\njust like usual."
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "show_notebook(os.path.join(\"nb\", \"other.ipynb\"))",
"execution_count": 14,
"outputs": [
{
"metadata": {},
"data": {
"text/plain": "<IPython.core.display.HTML at 0x1051de4d0>",
"text/html": "<h4>markdown cell</h4>\n<pre>This notebook just defines `bar`</pre>\n<h4>code cell</h4>\n<div class=\"highlight\"><pre><span class=\"k\">def</span> <span class=\"nf\">bar</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"s\">&quot;bar&quot;</span> <span class=\"o\">*</span> <span class=\"n\">x</span>\n</pre></div>\n"
},
"output_type": "display_data"
}
]
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "from nb import other\nother.bar(5)",
"execution_count": 15,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": "importing IPython notebook from nb/other.ipynb\n"
},
{
"metadata": {},
"data": {
"text/plain": "'barbarbarbarbar'"
},
"output_type": "execute_result",
"execution_count": 15
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "So now we have importable notebooks, from both the local directory and inside packages.\n\nI can even put a notebook inside IPython, to further demonstrate that this is working properly:"
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "import shutil\nfrom IPython.utils.path import get_ipython_package_dir\n\nutils = os.path.join(get_ipython_package_dir(), 'utils')\nshutil.copy(\"mynotebook.ipynb\", os.path.join(utils, \"inipython.ipynb\"))",
"execution_count": 16,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "and import the notebook from `IPython.utils`"
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "from IPython.utils import inipython\ninipython.whatsmyname()",
"execution_count": 17,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": "importing IPython notebook from /Users/minrk/Dropbox/dev/ip/mine/IPython/utils/inipython.ipynb\n"
},
{
"metadata": {},
"data": {
"text/plain": "'IPython.utils.inipython'"
},
"output_type": "execute_result",
"execution_count": 17
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Even Cython magics"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "With a bit of extra magic for handling the IPython interactive namespace during load,\neven magics like `%%cython` can be used:"
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "show_notebook('bs.ipynb')",
"execution_count": 18,
"outputs": [
{
"metadata": {},
"data": {
"text/plain": "<IPython.core.display.HTML at 0x1051de950>",
"text/html": "<h4>code cell</h4>\n<div class=\"highlight\"><pre><span class=\"o\">%</span><span class=\"n\">load_ext</span> <span class=\"n\">cythonmagic</span>\n</pre></div>\n\n<h4>markdown cell</h4>\n<pre>Python Black-Scholes</pre>\n<h4>code cell</h4>\n<div class=\"highlight\"><pre><span class=\"kn\">from</span> <span class=\"nn\">math</span> <span class=\"kn\">import</span> <span class=\"n\">exp</span><span class=\"p\">,</span> <span class=\"n\">sqrt</span><span class=\"p\">,</span> <span class=\"nb\">pow</span><span class=\"p\">,</span> <span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">erf</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">std_norm_cdf</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"o\">+</span><span class=\"n\">erf</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">/</span><span class=\"n\">sqrt</span><span class=\"p\">(</span><span class=\"mf\">2.0</span><span class=\"p\">)))</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">bs_py</span><span class=\"p\">(</span><span class=\"n\">s</span><span class=\"p\">,</span> <span class=\"n\">k</span><span class=\"p\">,</span> <span class=\"n\">t</span><span class=\"p\">,</span> <span class=\"n\">v</span><span class=\"p\">,</span> <span class=\"n\">rf</span><span class=\"p\">,</span> <span class=\"n\">div</span><span class=\"p\">,</span> <span class=\"n\">cp</span><span class=\"p\">):</span>\n <span class=\"sd\">&quot;&quot;&quot;Price an option using the Black-Scholes model.</span>\n<span class=\"sd\"> </span>\n<span class=\"sd\"> s : initial stock price</span>\n<span class=\"sd\"> k : strike price</span>\n<span class=\"sd\"> t : expiration time</span>\n<span class=\"sd\"> v : volatility</span>\n<span class=\"sd\"> rf : risk-free rate</span>\n<span class=\"sd\"> div : dividend</span>\n<span class=\"sd\"> cp : +1/-1 for call/put</span>\n<span class=\"sd\"> &quot;&quot;&quot;</span>\n <span class=\"n\">d1</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">log</span><span class=\"p\">(</span><span class=\"n\">s</span><span class=\"o\">/</span><span class=\"n\">k</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"p\">(</span><span class=\"n\">rf</span><span class=\"o\">-</span><span class=\"n\">div</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"nb\">pow</span><span class=\"p\">(</span><span class=\"n\">v</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span><span class=\"o\">*</span><span class=\"n\">t</span><span class=\"p\">)</span><span class=\"o\">/</span><span class=\"p\">(</span><span class=\"n\">v</span><span class=\"o\">*</span><span class=\"n\">sqrt</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">))</span>\n <span class=\"n\">d2</span> <span class=\"o\">=</span> <span class=\"n\">d1</span> <span class=\"o\">-</span> <span class=\"n\">v</span><span class=\"o\">*</span><span class=\"n\">sqrt</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span>\n <span class=\"n\">optprice</span> <span class=\"o\">=</span> <span class=\"n\">cp</span><span class=\"o\">*</span><span class=\"n\">s</span><span class=\"o\">*</span><span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"n\">div</span><span class=\"o\">*</span><span class=\"n\">t</span><span class=\"p\">)</span><span class=\"o\">*</span><span class=\"n\">std_norm_cdf</span><span class=\"p\">(</span><span class=\"n\">cp</span><span class=\"o\">*</span><span class=\"n\">d1</span><span class=\"p\">)</span> <span class=\"o\">-</span> \\\n <span class=\"n\">cp</span><span class=\"o\">*</span><span class=\"n\">k</span><span class=\"o\">*</span><span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"n\">rf</span><span class=\"o\">*</span><span class=\"n\">t</span><span class=\"p\">)</span><span class=\"o\">*</span><span class=\"n\">std_norm_cdf</span><span class=\"p\">(</span><span class=\"n\">cp</span><span class=\"o\">*</span><span class=\"n\">d2</span><span class=\"p\">)</span>\n <span class=\"k\">return</span> <span class=\"n\">optprice</span>\n</pre></div>\n\n<h4>markdown cell</h4>\n<pre>Cython Black-Scholes (the same, just with types)</pre>\n<h4>code cell</h4>\n<div class=\"highlight\"><pre><span class=\"o\">%%</span><span class=\"n\">cython</span>\n<span class=\"n\">cimport</span> <span class=\"n\">cython</span>\n<span class=\"kn\">from</span> <span class=\"nn\">libc.math</span> <span class=\"nn\">cimport</span> <span class=\"nn\">exp</span><span class=\"p\">,</span> <span class=\"n\">sqrt</span><span class=\"p\">,</span> <span class=\"nb\">pow</span><span class=\"p\">,</span> <span class=\"n\">log</span><span class=\"p\">,</span> <span class=\"n\">erf</span>\n\n<span class=\"nd\">@cython.cdivision</span><span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n<span class=\"n\">cdef</span> <span class=\"n\">double</span> <span class=\"n\">std_norm_cdf</span><span class=\"p\">(</span><span class=\"n\">double</span> <span class=\"n\">x</span><span class=\"p\">)</span> <span class=\"n\">nogil</span><span class=\"p\">:</span>\n <span class=\"k\">return</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"o\">+</span><span class=\"n\">erf</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">/</span><span class=\"n\">sqrt</span><span class=\"p\">(</span><span class=\"mf\">2.0</span><span class=\"p\">)))</span>\n\n<span class=\"nd\">@cython.cdivision</span><span class=\"p\">(</span><span class=\"bp\">True</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">bs_cy</span><span class=\"p\">(</span><span class=\"n\">double</span> <span class=\"n\">s</span><span class=\"p\">,</span> <span class=\"n\">double</span> <span class=\"n\">k</span><span class=\"p\">,</span> <span class=\"n\">double</span> <span class=\"n\">t</span><span class=\"p\">,</span> <span class=\"n\">double</span> <span class=\"n\">v</span><span class=\"p\">,</span>\n <span class=\"n\">double</span> <span class=\"n\">rf</span><span class=\"p\">,</span> <span class=\"n\">double</span> <span class=\"n\">div</span><span class=\"p\">,</span> <span class=\"n\">double</span> <span class=\"n\">cp</span><span class=\"p\">):</span>\n <span class=\"sd\">&quot;&quot;&quot;Same as above, with Cython&quot;&quot;&quot;</span>\n <span class=\"n\">cdef</span> <span class=\"n\">double</span> <span class=\"n\">d1</span><span class=\"p\">,</span> <span class=\"n\">d2</span><span class=\"p\">,</span> <span class=\"n\">optprice</span>\n <span class=\"k\">with</span> <span class=\"n\">nogil</span><span class=\"p\">:</span>\n <span class=\"n\">d1</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">log</span><span class=\"p\">(</span><span class=\"n\">s</span><span class=\"o\">/</span><span class=\"n\">k</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"p\">(</span><span class=\"n\">rf</span><span class=\"o\">-</span><span class=\"n\">div</span><span class=\"o\">+</span><span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"nb\">pow</span><span class=\"p\">(</span><span class=\"n\">v</span><span class=\"p\">,</span><span class=\"mi\">2</span><span class=\"p\">))</span><span class=\"o\">*</span><span class=\"n\">t</span><span class=\"p\">)</span><span class=\"o\">/</span><span class=\"p\">(</span><span class=\"n\">v</span><span class=\"o\">*</span><span class=\"n\">sqrt</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">))</span>\n <span class=\"n\">d2</span> <span class=\"o\">=</span> <span class=\"n\">d1</span> <span class=\"o\">-</span> <span class=\"n\">v</span><span class=\"o\">*</span><span class=\"n\">sqrt</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span>\n <span class=\"n\">optprice</span> <span class=\"o\">=</span> <span class=\"n\">cp</span><span class=\"o\">*</span><span class=\"n\">s</span><span class=\"o\">*</span><span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"n\">div</span><span class=\"o\">*</span><span class=\"n\">t</span><span class=\"p\">)</span><span class=\"o\">*</span><span class=\"n\">std_norm_cdf</span><span class=\"p\">(</span><span class=\"n\">cp</span><span class=\"o\">*</span><span class=\"n\">d1</span><span class=\"p\">)</span> <span class=\"o\">-</span> \\\n <span class=\"n\">cp</span><span class=\"o\">*</span><span class=\"n\">k</span><span class=\"o\">*</span><span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"n\">rf</span><span class=\"o\">*</span><span class=\"n\">t</span><span class=\"p\">)</span><span class=\"o\">*</span><span class=\"n\">std_norm_cdf</span><span class=\"p\">(</span><span class=\"n\">cp</span><span class=\"o\">*</span><span class=\"n\">d2</span><span class=\"p\">)</span>\n <span class=\"k\">return</span> <span class=\"n\">optprice</span>\n</pre></div>\n\n<h4>code cell</h4>\n<div class=\"highlight\"><pre>\n</pre></div>\n"
},
"output_type": "display_data"
}
]
},
{
"metadata": {
"collapsed": false,
"trusted": false
},
"cell_type": "code",
"source": "from bs import bs_py, bs_cy\nprint \"Python\"\n%timeit bs_py(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)\nprint \"Cython\"\n%timeit bs_cy(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)",
"execution_count": 19,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": "importing IPython notebook from bs.ipynb\nPython\n100000 loops, best of 3: 3.03 µs per loop\nCython\n1000000 loops, best of 3: 367 ns per loop\n"
}
]
},
{
"metadata": {},
"cell_type": "markdown",
"source": "*This notebook is by Min Ragan-Kelley, and placed in the public domain*"
}
],
"metadata": {
"gist_id": "6011986",
"kernelspec": {
"name": "python3",
"display_name": "Python 3",
"language": "python"
},
"language_info": {
"file_extension": ".py",
"nbconvert_exporter": "python",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"version": "3.4.3",
"pygments_lexer": "ipython3",
"name": "python",
"mimetype": "text/x-python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment