# iPython & jupyter notebook introduction¶

Help functionality and tab completion
`?` command returns the docstring of the corresponding method, class, etc.
`help(.)` gives the full documentation.

In [1]:

    dict?

In [2]:

    help(dict)

    Help on class dict in module builtins:

    class dict(object)
     |  dict() -> new empty dictionary
     |  dict(mapping) -> new dictionary initialized from a mapping object's
     |      (key, value) pairs
     |  dict(iterable) -> new dictionary initialized as if via:
     |      d = {}
     |      for k, v in iterable:
     |          d[k] = v
     |  dict(**kwargs) -> new dictionary initialized with the name=value pairs
     |      in the keyword argument list.  For example:  dict(one=1, two=2)
     |
     |  Methods defined here:
     |
     |  __contains__(self, key, /)
     |      True if the dictionary has the specified key, else False.
     |
     |  __delitem__(self, key, /)
     |      Delete self[key].
     |
     |  __eq__(self, value, /)
     |      Return self==value.
     |
     |  __ge__(self, value, /)
     |      Return self>=value.
     |
     |  __getattribute__(self, name, /)
     |      Return getattr(self, name).
     |
     |  __getitem__(...)
     |      x.__getitem__(y) <==> x[y]
     |
     |  __gt__(self, value, /)
     |      Return self>value.
     |
     |  __init__(self, /, *args, **kwargs)
     |      Initialize self.  See help(type(self)) for accurate signature.
     |
     |  __iter__(self, /)
     |      Implement iter(self).
     |
     |  __le__(self, value, /)
     |      Return self<=value.
     |
     |  __len__(self, /)
     |      Return len(self).
     |
     |  __lt__(self, value, /)
     |      Return self<value.
     |
     |  __ne__(self, value, /)
     |      Return self!=value.
     |
     |  __repr__(self, /)
     |      Return repr(self).
     |
     |  __setitem__(self, key, value, /)
     |      Set self[key] to value.
     |
     |  __sizeof__(...)
     |      D.__sizeof__() -> size of D in memory, in bytes
     |
     |  clear(...)
     |      D.clear() -> None.  Remove all items from D.
     |
     |  copy(...)
     |      D.copy() -> a shallow copy of D
     |
     |  get(self, key, default=None, /)
     |      Return the value for key if key is in the dictionary, else default.
     |
     |  items(...)
     |      D.items() -> a set-like object providing a view on D's items
     |
     |  keys(...)
     |      D.keys() -> a set-like object providing a view on D's keys
     |
     |  pop(...)
     |      D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
     |      If key is not found, d is returned if given, otherwise KeyError is raised
     |
     |  popitem(...)
     |      D.popitem() -> (k, v), remove and return some (key, value) pair as a
     |      2-tuple; but raise KeyError if D is empty.
     |
     |  setdefault(self, key, default=None, /)
     |      Insert key with a value of default if key is not in the dictionary.
     |
     |      Return the value for key if key is in the dictionary, else default.
     |
     |  update(...)
     |      D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
     |      If E is present and has a .keys() method, then does:  for k in E: D[k] = E[k]
     |      If E is present and lacks a .keys() method, then does:  for k, v in E: D[k] = v
     |      In either case, this is followed by: for k in F:  D[k] = F[k]
     |
     |  values(...)
     |      D.values() -> an object providing a view on D's values
     |
     |  ----------------------------------------------------------------------
     |  Class methods defined here:
     |
     |  fromkeys(iterable, value=None, /) from builtins.type
     |      Create a new dictionary with keys from iterable and values set to value.
     |
     |  ----------------------------------------------------------------------
     |  Static methods defined here:
     |
     |  __new__(*args, **kwargs) from builtins.type
     |      Create and return a new object.  See help(type) for accurate signature.
     |
     |  ----------------------------------------------------------------------
     |  Data and other attributes defined here:
     |
     |  __hash__ = None

In [7]:

    a = {"a":1,"b":2}

`?` can also be applied to instances

In [8]:

    a?

iPython supports tab completion giving the list of available functions or for a function a description of the function singature.

In [9]:

    a.update({"c":3})

In [10]:

    a.keys()

Out[10]:

    dict_keys(['a', 'b', 'c'])

Run scripts and use system shell commmands
`!` allows to invoke system shell commands.
With `run` we can invoke python scripts in an iPython shell

In [11]:

    !ls

    Lecture_ipython.ipynb script.py

In [12]:

    run script.py

    Hello, I am a script!

`%load <filename>` loads the content of the file into the cell

In [14]:

    # %load script.py
    #!/usr/bin/python

    import sys

    if __name__ == '__main__':
    	print("Hello, I am a script!")

    Hello, I am a script!

Magic function
iPython comes with a set of functions that can be called in a command-line style.
`%` runs the line as a command, `%%` the whole cell, `time` and `timeit` are two examples (single and statistical evaluation)

In [15]:

    %time a = 1

    CPU times: user 3 µs, sys: 0 ns, total: 3 µs
    Wall time: 5.01 µs

In [16]:

    %%time
    for _ in range(int(1e6)):
        pass

    CPU times: user 45.7 ms, sys: 1.67 ms, total: 47.4 ms
    Wall time: 46.6 ms

user refers to the time spent to execute the command, sys refers to the time spent in the kernel

In [17]:

    %timeit a = 1

    10.7 ns ± 0.0605 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)

In [18]:

    %%timeit
    for _ in range(int(1e6)):
        pass

    19.9 ms ± 523 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [19]:

    a = %run script.py

    Hello, I am a script!

In [21]:

    t = %time dict()

    CPU times: user 4 µs, sys: 0 ns, total: 4 µs
    Wall time: 6.91 µs

In [23]:

    %%debug
    a = 3
    for _ in range(a):
        a+=1
    print("End")

    NOTE: Enter 'c' at the ipdb>  prompt to continue execution.
    > <string>(2)<module>()

    ipdb> n
    > <string>(3)<module>()

    ipdb> n
    > <string>(4)<module>()

    ipdb> n
    > <string>(3)<module>()

    ipdb> n
    > <string>(4)<module>()

    ipdb> n
    > <string>(3)<module>()

    ipdb> n
    > <string>(4)<module>()

    ipdb> n
    > <string>(3)<module>()

    ipdb> n
    > <string>(5)<module>()

    ipdb> n
    End
    --Return--
    None
    > <string>(5)<module>()

    ipdb> n

In [24]:

    %%perl
    use strict;

    my $a = 5;
    while($a > 0) {
        print "$a ";
        $a--;
    }
    print "\n";

    5 4 3 2 1

In [26]:

    %%perl
    # Function definition
    sub Hello {
       print "Hello, World!\n";
    }
    Hello()

    Hello, World!

In [27]:

    %%latex
    $$a=1+\gamma$$
    Some text
    \begin{eqnarray}
    a^2+b^2 &=&c^2\\
    x&=&y
    \end{eqnarray}

$$a=1+\gamma$$ Some text \begin{eqnarray} a^2+b^2 &=&c^2\\ x&=&y \end{eqnarray}
In [28]:

    %load_ext rpy2.ipython

In [29]:

    %%R
    library(lattice)
    attach(mtcars)

    # scatterplot matrix
    splom(mtcars[c(1,3,4,5,6)], main="MTCARS Data")

### Documentation¶

Markdown text can be used to document your work. HTML and custom tags allow you to structure your text and explain your `code`, for example what a list comprehension is `squares = [n**2 for n in numbers]`.
And even LaTeX code can be used in markdown cells: $\nabla f = (\partial_x f,\partial_y f,\partial_z f)$

In [ ]: