Skip to main content

Dynamic classes for Jupyter/IPython notebooks.

Project description

# jdc - Jupyter Dynamic Classes

*Alex Hagen*

``jdc`` is a Jupyter magic made to solve a very specific problem: that sometimes
you want to define classes dynamically in Jupyter notebooks, and you want it to
look good. On
[Jupyter's Github](https://github.com/jupyter/notebook/issues/1243) there's a
lengthy discussion and wider view of this issue, but I've implemented a quickfix
which I think ended up looking pretty semantic. Thanks to
[Igor Sobreira](http://igorsobreira.com/2011/02/06/adding-methods-dynamically-in-python.html)
for the underlying IPython.

The example below will be most informative, but basically all ``jdc`` allows you
to do is to add a cell and define

```python
%%add_to our_class
def our_function(self, our_variable):
print our_variable
```

and that will add the method ``our_function`` to ``our_class``, whether
``our_class`` is a class, or an object with a class type.

<div class="cell border-box-sizing text_cell rendered">

<div class="prompt input_prompt">

</div>

<div class="inner_cell">

<div class="text_cell_render border-box-sizing rendered_html">

Example[¶](#Example){.anchor-link} {#Example}
===================================

</div>

</div>

</div>

<div class="cell border-box-sizing text_cell rendered">

<div class="prompt input_prompt">

</div>

<div class="inner_cell">

<div class="text_cell_render border-box-sizing rendered_html">

Below is an example on how to use `jdc`. First we have to import the
class:

</div>

</div>

</div>

<div class="cell border-box-sizing code_cell rendered">

<div class="input">

<div class="prompt input_prompt">

In \[1\]:

</div>

<div class="inner_cell">

<div class="input_area">

<div class="highlight hl-ipython2">

import jdc

</div>

</div>

</div>

</div>

</div>

<div class="cell border-box-sizing text_cell rendered">

<div class="prompt input_prompt">

</div>

<div class="inner_cell">

<div class="text_cell_render border-box-sizing rendered_html">

Then, we have to make a dummy class:

</div>

</div>

</div>

<div class="cell border-box-sizing code_cell rendered">

<div class="input">

<div class="prompt input_prompt">

In \[2\]:

</div>

<div class="inner_cell">

<div class="input_area">

<div class="highlight hl-ipython2">

class dog(object):
def __init__(self, name, noise):
self.name = name
self.noise = noise


rover = dog('Rover', 'ruff')
spot = dog('Spot', 'woof')

</div>

</div>

</div>

</div>

</div>

<div class="cell border-box-sizing text_cell rendered">

<div class="prompt input_prompt">

</div>

<div class="inner_cell">

<div class="text_cell_render border-box-sizing rendered_html">

Then, we want to add a function to that class:

</div>

</div>

</div>

<div class="cell border-box-sizing code_cell rendered">

<div class="input">

<div class="prompt input_prompt">

In \[3\]:

</div>

<div class="inner_cell">

<div class="input_area">

<div class="highlight hl-ipython2">

%%add_to dog
def bark(self, times=1):
saying = ('%s ' % self.noise) * times
print "%s says: %s" % (self.name, saying)

def bark2(self, times=1):
saying = ('%s ' % self.noise) * times
print "%s says: %s" % (self.name, saying)

</div>

</div>

</div>

</div>

</div>

<div class="cell border-box-sizing text_cell rendered">

<div class="prompt input_prompt">

</div>

<div class="inner_cell">

<div class="text_cell_render border-box-sizing rendered_html">

And now we can access that function from any method of that class.

</div>

</div>

</div>

<div class="cell border-box-sizing code_cell rendered">

<div class="input">

<div class="prompt input_prompt">

In \[4\]:

</div>

<div class="inner_cell">

<div class="input_area">

<div class="highlight hl-ipython2">

rover.bark(1)
spot.bark(2)

</div>

</div>

</div>

</div>

<div class="output_wrapper">

<div class="output">

<div class="output_area">

<div class="prompt">

</div>

<div class="output_subarea output_stream output_stdout output_text">

Rover says: ruff
Spot says: woof woof

</div>

</div>

</div>

</div>

</div>

<div class="cell border-box-sizing text_cell rendered">

<div class="prompt input_prompt">

</div>

<div class="inner_cell">

<div class="text_cell_render border-box-sizing rendered_html">

If we want to add a function to only one object of that class, we can do
that, as well:

</div>

</div>

</div>

<div class="cell border-box-sizing code_cell rendered">

<div class="input">

<div class="prompt input_prompt">

In \[5\]:

</div>

<div class="inner_cell">

<div class="input_area">

<div class="highlight hl-ipython2">

%%add_to spot
def sit(self):
print '%s is now sitting' % self.name

</div>

</div>

</div>

</div>

</div>

<div class="cell border-box-sizing code_cell rendered">

<div class="input">

<div class="prompt input_prompt">

In \[6\]:

</div>

<div class="inner_cell">

<div class="input_area">

<div class="highlight hl-ipython2">

spot.sit()

</div>

</div>

</div>

</div>

<div class="output_wrapper">

<div class="output">

<div class="output_area">

<div class="prompt">

</div>

<div class="output_subarea output_stream output_stdout output_text">

Spot is now sitting

</div>

</div>

</div>

</div>

</div>

<div class="cell border-box-sizing text_cell rendered">

<div class="prompt input_prompt">

</div>

<div class="inner_cell">

<div class="text_cell_render border-box-sizing rendered_html">

Note that the function added to a class object is only available to that
object, not all objects of that class:

</div>

</div>

</div>

<div class="cell border-box-sizing code_cell rendered">

<div class="input">

<div class="prompt input_prompt">

In \[7\]:

</div>

<div class="inner_cell">

<div class="input_area">

<div class="highlight hl-ipython2">

try:
rover.sit()
except AttributeError:
print "%s doesn't know that trick" % rover.name

</div>

</div>

</div>

</div>

<div class="output_wrapper">

<div class="output">

<div class="output_area">

<div class="prompt">

</div>

<div class="output_subarea output_stream output_stdout output_text">

Rover doesn't know that trick

</div>

</div>

</div>

</div>

</div>

<div class="cell border-box-sizing text_cell rendered">

<div class="prompt input_prompt">

</div>

<div class="inner_cell">

<div class="text_cell_render border-box-sizing rendered_html">

And if we're writing a lot of code, we can now do that in a single cell.

</div>

</div>

</div>

<div class="cell border-box-sizing code_cell rendered">

<div class="input">

<div class="prompt input_prompt">

In \[8\]:

</div>

<div class="inner_cell">

<div class="input_area">

<div class="highlight hl-ipython2">

%%add_to spot
def rollover(self):
print "%s rolled over" % self.name

def highfive(self):
print "%s is trying to high five you" % self.name

def domytaxes(self):
print "%s is just showing off now" % self.name

</div>

</div>

</div>

</div>

</div>

<div class="cell border-box-sizing code_cell rendered">

<div class="input">

<div class="prompt input_prompt">

In \[9\]:

</div>

<div class="inner_cell">

<div class="input_area">

<div class="highlight hl-ipython2">

spot.rollover()
spot.highfive()
spot.domytaxes()

</div>

</div>

</div>

</div>

<div class="output_wrapper">

<div class="output">

<div class="output_area">

<div class="prompt">

</div>

<div class="output_subarea output_stream output_stdout output_text">

Spot rolled over
Spot is trying to high five you
Spot is just showing off now

</div>

</div>

</div>

</div>

</div>

<div class="cell border-box-sizing text_cell rendered">

<div class="prompt input_prompt">

</div>

<div class="inner_cell">

<div class="text_cell_render border-box-sizing rendered_html">

Nesting functions and decorators should now work. Notice when calling
the wrapped function that we must call it by `func(self, *args)` instead
of `self.func(*args)` or `func(*args)`.

</div>

</div>

</div>

<div class="cell border-box-sizing code_cell rendered">

<div class="input">

<div class="prompt input_prompt">

In \[10\]:

</div>

<div class="inner_cell">

<div class="input_area">

<div class="highlight hl-ipython2">

%%add_to dog
def race(func):
def wrapper(self):
import time
t1 = time.time()
func(self)
t2 = time.time()
print "A new record time, %s finished in: " % self.name + str((t2 - t1)) + " seconds!\n"
return wrapper

@race
def race_course(self):
print "%s finished the course." % self.name

</div>

</div>

</div>

</div>

</div>

<div class="cell border-box-sizing code_cell rendered">

<div class="input">

<div class="prompt input_prompt">

In \[11\]:

</div>

<div class="inner_cell">

<div class="input_area">

<div class="highlight hl-ipython2">

spot.race_course()

</div>

</div>

</div>

</div>

<div class="output_wrapper">

<div class="output">

<div class="output_area">

<div class="prompt">

</div>

<div class="output_subarea output_stream output_stdout output_text">

Spot finished the course.
A new record time, Spot finished in: 0.000334978103638 seconds!

</div>

</div>

</div>

</div>

</div>

<div class="cell border-box-sizing text_cell rendered">

<div class="prompt input_prompt">

</div>

<div class="inner_cell">

<div class="text_cell_render border-box-sizing rendered_html">

and that's it.

</div>

</div>

</div>

## Installation

Right now, installation should now work through PyPI:

```bash

pip install jdc

```

Please open up an issue if it doesn't work, I'll fix it!


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jdc-0.0.8.tar.gz (57.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jdc-0.0.8-py2.py3-none-any.whl (6.4 kB view details)

Uploaded Python 2Python 3

File details

Details for the file jdc-0.0.8.tar.gz.

File metadata

  • Download URL: jdc-0.0.8.tar.gz
  • Upload date:
  • Size: 57.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for jdc-0.0.8.tar.gz
Algorithm Hash digest
SHA256 19d099a918f6d6b8607d0ec1a82644ed3962b004e34aac80444cc4e68c776237
MD5 2487685b4ff5cc90adc51527c7a23f1a
BLAKE2b-256 208f174193796b5459012df2c639bddac9c4af25c6d95231eef30a65c4fe2490

See more details on using hashes here.

File details

Details for the file jdc-0.0.8-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for jdc-0.0.8-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 ab4e2f48befef7b06067e853ff417f9ff5882b0203d22a67791e7153455fc654
MD5 48065eddf5a8a6a4ba33ce2e95911451
BLAKE2b-256 a337a5d24a24d90e5be458ce5c85f623d1d4abc8a8f1adcd90fae72219f00fb5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page