Python 3 tutorial (long version)

Why learning python ?

  • The need for an interpreted language.
  • The Python syntax is very easy.
  • It is an Oriented Object Programming (OOP) language.
  • It contains an exteremely huge number of modules (libraries).
  • Python is widely used in astrophysics (astropy).
  • You can do everything with python !
  • Python can be extended with C.
  • Python is an evoloving language : Python2, Python3…
  • Excellent remedy againts headaches.

References

Python2 / Python3 compatibility

Using python with the interpreter

Using python with the interpreter:

$ python3
[GCC 7.3.1 20180303 (Red Hat 7.3.1-5)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

or using the more advanced interactive python interperter ipython:

$ ipython3
[revaz@xps-revaz Doc]$ ipython3
Python 3.6.4 (default, Mar 13 2018, 18:18:20)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]:

Simple examples:

>>> x=1
>>> y=2.
>>> type(x)
<class 'int'>
>>> type(y)
<class 'float'>
>>>

Operations on numbers:

>>> x+y
3.0
>>> type(x+y)
<class 'float'>
>>> z = x+y
>>> x==y
False
>>> x!=y
True
>>> x>y
False
>>> 17 / 3      # classic division returns a float
5.666666666666667
>>>
>>> 17 // 3     # floor division discards the fractional part
5
>>> 17 % 3      # the % operator returns the remainder of the division
2

Basic python objects

Integers

>>> x=1

Floats

>>> y=2.

Strings

Strings are defined using simple quote ', double quote ", ''' or """

>>> name = "Python"
>>> name
'Python'
>>> name = 'Python'
>>> name
'Python'

it is possible to mulitply and add strings:

>>> 3 * 'py' + 'thon'
'pypypython'

>>> print("1\n2\n3")
1
2
3

Strings can be indexed:

`` +---+---+---+---+---+---+``
`` | P | y | t | h | o | n |``
`` +---+---+---+---+---+---+``
`` 0   1   2   3   4   5   6``
``-6  -5  -4  -3  -2  -1    ``
>>> name[0]
'P'
>>> name[2:4]
'th'
>>> name[4:]
'on'
>>> name[-1]
'n'
>>> name[-5:-1]
'ytho'

But they are immutable:

>>> name[1] = "p"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

Lists

A Python list defines an ordered list of python objects. They are defined with [] or list(): Unlike strings, which are immutable, lists are a mutable type, i.e. it is possible to change their content:

>>> trousse=['gommme', 'crayon', 'plume', 1, 1.2]
>>> type(trousse)
<type 'list'>
>>> trousse[0]
'gommme'
>>> trousse[-1]
1.2
>>> trousse.index('crayon')
1
>>> trousse.count('plume')
2
>>> trousse.pop()
1.2
>>> trousse.pop()
1
>>> trousse.append("compas")
>>> trousse
['gommme', 'crayon', 'plume', 1, 'compas']
>>> trousse[3] = "stylo"
>>> trousse
['gommme', 'crayon', 'plume', 'stylo', 'compas']
>>> len(trousse)
5

>>> list("abcd")
['a', 'b', 'c', 'd']

Dictionaries

Dictionaries are sets of python objects indexed by keys. They are defined with {} or dict()

>>> onglet={'observatoire':'obswww.unige.ch','tsr':'www.tsr.ch'}
>>> type(onglet)
<type 'dict'>
>>> onglet=dict(observatoire='obswww.unige.ch',tsr='www.tsr.ch')
>>> onglet
{'observatoire': 'obswww.unige.ch', 'tsr': 'www.tsr.ch'}
>>> onglet['observatoire']
'obswww.unige.ch'
>>> onglet['tsr']
'www.tsr.ch'
>>> onglet['epfl'] = "www.epfl.ch"
>>> onglet.keys()
['epfl', 'tsr', 'observatoire']
>>> 'tsr' in onglet
True
>>> del onglet['tsr']
>>> onglet
{'observatoire': 'obswww.unige.ch', 'epfl': 'www.epfl.ch'}

Warning

The del statement is used to delete an object (removed from the Python memory).

example:

>>> x = 1
>>> x
1
>>> del x
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

It might be used to remove an element from a list or from a dictonnary:

>>> x = [1,2,3]
>>> del x[1]
>>> x
[1, 3]

Tuples

A tuple consists of a number python objects separated by commas or commas and ().

>>> t = 12345, 54321, 'hello!'
>>> type(t)
<class 'tuple'>
>>> t = (12345, 54321, 'hello!')
>>> type(t)
<class 'tuple'>
>>> t
(12345, 54321, 'hello!')
>>> t[0]
12345

Tuples are immutable:

>>> t[0] = 12
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> len(t)
3

>>> x,y,z = t
>>> x
12345
>>> y
54321
>>> z
'hello!'
>>>

Sets

A set is an unordered collection of python objects with no duplicate elements. As dictionaries they are defined with {} or set():

>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> basket
set(['orange', 'pear', 'apple', 'banana'])
>>> set("salut")
set(['a', 's', 'u', 'l', 't'])


>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a                                  # unique letters in a
{'a', 'r', 'b', 'c', 'd'}
>>> a - b                              # letters in a but not in b
{'r', 'd', 'b'}
>>> a | b                              # letters in a or b or both
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b                              # letters in both a and b
{'a', 'c'}
>>> a ^ b                              # letters in a or b but not both
{'r', 'd', 'b', 'm', 'z', 'l'}

Control Flow Tools

  • if/else/for/while/range/break/continue/pass

if:

>>> x = 0
>>> if x==1:
...   print("x equal 1")
... else:
...   print("x is not equal to 1")
...
x is not equal to 1

Warning

In Python, a block (a group of statements) is defined by its indentation:

for:

>>> for x in trousse:
...   print(x)
...
crayon
plume
stylo
compas


>>> for x in range(10):
...   print(x)
...
0
1
2
3
4
5
6
7
8
9

break: quit the loop:

>>> for x in range(10):
...   print(x)
...   if x==5:
...     break
...
0
1
2
3
4
5

continue: jump to the next loop:

>>> for x in range(10):
...   if x==5:
...     continue
...     print("x equal 5")
...   print(x)
...
0
1
2
3
4
6
7
8
9

pass: does nothing:

>>> for x in range(10):
...   if x==5:
...     pass
...   print(x)
...
0
1
2
3
4
5
6
7
8
9

while: do a loop while a condition is true:

>>> x = 0
>>> while(x<5):
...   print(x)
...   x+=1
...
0
1
2
3
4

Warning

In Python, comments are defined by #.

example:

# loop from 1 to n-1
for a in range(1,n):
  # loop from a to n-1
  for b in range(a,n):
    c_square = a**2 + b**2
    c = int(sqrt(c_square))

    if ((c_square - c**2) == 0):
         print(a, b, c)

Looping Techniques

Looping through lists

example:

>>> for x in trousse:
...   print(x)
...
crayon
plume
stylo
compas

the position index and corresponding value can be retrieved at the same time:

>>> for i,x in enumerate(trousse):
...   print(i,x)
...
0 gommme
1 crayon
2 plume
3 stylo
4 compas

looping through lists in reversed order:

>>> for i in reversed(range(10)):
...   print(i)
...
9
8
7
6
5
4
3
2
1
0

looping through two lists:

>>> x = ["Jean-Paul","Pascale","Fred"]
>>> y = [1,2,3]
>>> for name, number in zip(x, y):
...   print(number,name)
...
1 Jean-Paul
2 Pascale
3 Fred

Looping through dictionaries

>>> for name, url in onglet.items():
...   print(name, url)
...
observatoire obswww.unige.ch
epfl www.epfl.ch

Defining python objects through loops

lists:

>>> squares = [x**2 for x in range(10)]
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

list of tuples with conditions:

>>> z = [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
>>> z
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

dictionaries:

>>> d = {x: x**2 for x in (2, 4, 6)}
>>> d
{2: 4, 4: 16, 6: 36}

sets:

>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}

Functions

Defining functions:

>>> def multiply(x,y):
...   z = x*y
...   return z
...
>>> multiply(2,3)
6

Return multiple values:

>>> def divide(x,y):
...   floor     = x // y
...   remainder = x % y
...   return floor,remainder
...
>>> divide(17,3)
(5, 2)
>>> type(divide(17,3))
<class 'tuple'>

Warning

In the function, the type of arguments are not defined.

What do we get if we type multiply("a","b") or multiply(3,"b") ?

Defining functions with optional arguments:

>>> def multiply(x,y,verbose=False):
...   if verbose:
...     print("computing x*y")
...   z = x*y
...   return z
...
>>> multiply(2,3)
6
>>> multiply(2,3,True)
computing x*y
6
>>> multiply(2,3,verbose=True)
computing x*y
6
>>>

The default values are evaluated at the point of function definition:

>>> i=5
>>> def f(x=i):
...   print(x)
...
>>> i=6
>>> f()
5

Mutable objects as default arguements… some surprises…:

>>> def f(a, L=[]):
...   L.append(a)
...   return L
...
>>> print(f(1))
[1]
>>> print(f(2))
[1, 2]
>>> print(f(3))
[1, 2, 3]

Arbitrary argument lists with or without keywords:

>>> def f(*args, **kwargs):
...   print(args)
...   print(kwargs)
...
>>> f()
()
{}
>>> f("a","b","c")
('a', 'b', 'c')
{}
>>> f("a","b","c",d=1,e=2,f=3)
('a', 'b', 'c')
{'d': 1, 'e': 2, 'f': 3}
>>>

Unpacking argument lists or tuple or dictionaries:

>>> def f(x,y,z=1):
...   print(x,y,z)
...
>>> args = (1,2)
>>> kwargs = {"x":3,"y":4,"z":5}
>>> f(*args)
1 2 1
>>> f(**kwargs)
3 4 5

Lambda expressions: small anonymous functions. They can be used wherever function objects are required:

>>> f = lambda x: x + 1
>>> type(f)
<class 'function'>
>>> f(3)
4

with two arguements:

>>> sum = lambda x,y: x + y
>>> type(sum)
<class 'function'>
>>> sum(3,4)
7

A function that create a function…:

>>> def make_incrementor(n):
...   return lambda x:x+n
...
>>> f = make_incrementor(10)
>>> f(100)
110

Sorting lists:

>>> x = ["Jean-Paul","Pascale","Fred","Pierre"]
>>> x.sort()
>>> x
['Fred', 'Jean-Paul', 'Pascale', 'Pierre']
>>> x.sort(key=lambda x:len(x))
>>> x
['Fred', 'Pierre', 'Pascale', 'Jean-Paul']

map() applies a function to all the items in an input list:

>>> def x2(x):
...   return x**2
...
>>> list(map(x2,range(10)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

the same with lambda in one line:

>>> list(map(lambda x:x**2,range(10)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Input and Output

Formatting

print a number:

>>> 3.141592653589793
3.141592653589793

create a string:

>>> '{}'.format(3.141592653589793)
'3.141592653589793'

use multiple arguements:

>>> '{} {} '.format(3.141592653589793,2.718281828459045)
'3.141592653589793 2.718281828459045 '

make the string more complex:

>>> 'pi={} and e={} '.format(3.141592653589793,2.718281828459045)
'pi=3.141592653589793 and e=2.718281828459045 '
>>> 'e={1} and pi={0} '.format(3.141592653589793,2.718281828459045)
'e=2.718281828459045 and pi=3.141592653589793 '

format number with resp. 3 and 5 decimals:

>>> 'pi={0:5.3f} and e={1:7.5f} '.format(3.141592653589793,2.718281828459045)
'pi=3.142 and e=2.71828 '

exponent notation:

>>> 'pi={0:e} and e={1:e} '.format(3.141592653589793,2.718281828459045)
'pi=3.141593e+00 and e=2.718282e+00 '

general format:

>>> 'pi={0:g} and e={1:g} '.format(3.141592653589793,2.718281828459045)
'pi=3.14159 and e=2.71828 '

integer format:

>>> 'pi={0:003d} and e={1:005d} '.format(3,2)
'pi=003 and e=00002 '

Accessing arguments by name:

>>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W')
'Coordinates: 37.24N, -115.81W'

Aligning the text and specifying a width:

>>> '{:<30}'.format('left aligned')
'left aligned                  '
>>> '{:>30}'.format('right aligned')
'                 right aligned'
>>> '{:^30}'.format('centered')
'           centered

with numbers:

>>> for i in range(20):
...   '{:>10}{:>15.5f}'.format(2**i,(2**i)/3.)
...
'         1        0.33333'
'         2        0.66667'
'         4        1.33333'
'         8        2.66667'
'        16        5.33333'
'        32       10.66667'
'        64       21.33333'
'       128       42.66667'
'       256       85.33333'
'       512      170.66667'
'      1024      341.33333'
'      2048      682.66667'
'      4096     1365.33333'
'      8192     2730.66667'
'     16384     5461.33333'
'     32768    10922.66667'
'     65536    21845.33333'
'    131072    43690.66667'
'    262144    87381.33333'
'    524288   174762.66667'

Formating from lists or tuples:

>>> squares = [x**2 for x in range(10)]
>>> "{0[0]} {0[1]} ... {0[8]} {0[9]}".format(squares)
'0 1 ... 64 81'

Files

Open and write into a file:

>>> f=open('file.txt','w')
>>> f.write("See how python is easy !\n")
>>> f.close()

Open and read a file:

>>> f=open('file.txt','r')
>>> line = f.readline()
>>> f.close()
>>> line
'See how python is easy !\n'

Write/read multiples lines:

>>> f=open('file.txt','w')
>>> for i in range(10):
...   f.write("This is line %d.\n"%i)
...
16
16
16
16
16
16
16
16
16
16
>>> f.close()


>>> f=open('file.txt','r')
>>> lines = f.readlines()
>>> f.close()
>>> lines
['This is line 0.\n', 'This is line 1.\n', 'This is line 2.\n', 'This is line 3.\n', 'This is line 4.\n', 'This is line 5.\n', 'This is line 6.\n', 'This is line 7.\n', 'This is line 8.\n', 'This is line 9.\n']
>>> for i,line in enumerate(lines):
...   print(line)
...
This is line 0.

This is line 1.

This is line 2.

This is line 3.

This is line 4.

This is line 5.

This is line 6.

This is line 7.

This is line 8.

This is line 9.

Saving structured data with pickle

>>> import pickle
>>> d = {x: x**2 for x in range(10)}
>>> l = [x**2 for x in range(10)]
>>> f = open("squares.pkl",'wb')
>>> pickle.dump(d,f)
>>> pickle.dump(l,f)
>>> f.close()

Warning

the file must be opened in wb mode (write, binary)

now, recover the values:

>>> pickle.load(f)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> f.close()
>>> f = open("squares.pkl",'rb')
>>> d = pickle.load(f)
>>> l = pickle.load(f)
>>> f.close()
>>> d
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
>>> l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Saving structured data with json

Use json instead of pickle ! json is not a pure Python format.

Store in a json file:

>>> import json
>>> d = {x: x**2 for x in range(10)}
>>> l = [x**2 for x in range(10)]
>>> f = open("squares.json",'w')
>>> json.dump([d,l], f)
>>> f.close()

Warning

the file must be opened in w mode (write only)

Recover values:

>>> import json
>>> f = open("squares.json",'r')
>>> data = json.load(f)
>>> f.close()
>>> d = data[0]
>>> l = data[1]

Scripting python

  1. open/create a file:

    $ gedit myscript.py
    
  2. add a shebang (unix file header):

    #!/usr/bin/env python
    
  3. add your python commands:

    #!/usr/bin/env python
    
    for i in range(10):
      print("Hello world ! from loop {}".format(i))
    
  4. save the file

  5. make it executable:

    $ chmod a+x myscript.py
    

    or (if you want to avoid other people to execute it):

    $ chmod u+x myscript.py
    
  6. launch it !:

    $ ./myscript.py
    Hello world ! from loop 0
    Hello world ! from loop 1
    Hello world ! from loop 2
    Hello world ! from loop 3
    Hello world ! from loop 4
    Hello world ! from loop 5
    Hello world ! from loop 6
    Hello world ! from loop 7
    Hello world ! from loop 8
    Hello world ! from loop 9
    
  7. Alternatively, you don’t need to make the file executable, but can run it by calling python:

    $ python3 ./myscript.py
    

Modules

A module is a file containing Python definitions and statements. It works a bit like libraries in C or Fortran. The file name is the module name with the suffix .py appended.

Example: create the file mymodule.py:

pi = 3.141592653589793

def x2(x):
  return x*x

def degtorad(t):
  return pi/180.*t

How to import the module:

  1. import all the module content locally:

    >>> from mymodule import *
    >>> pi
    3.141592653589793
    >>> x2(2)
    4
    >>> degtorad(180)
    3.141592653589793
    

Warning

This may erase local variables…

  1. import the module as mymodule:

    >>> import mymodule
    >>> mymodule.pi
    3.141592653589793
    >>> mymodule.x2(2)
    4
    >>> mymodule.degtorad(180)
    3.141592653589793
    
  2. import the module under another name:

    >>> import mymodule as mymod
    >>> mymod.pi
    3.141592653589793
    >>> mymod.x2(2)
    4
    >>> mymod.degtorad(180)
    3.141592653589793
    
  3. import only some functions from the module:

    >>> from mymodule import x2,degtorad
    >>> x2(2)
    4
    >>> degtorad(180)
    3.141592653589793
    >>> pi
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'pi' is not defined
    
  4. import only some functions from the module and change its name:

    >>> from mymodule import x2 as square
    >>> square(2)
    4
    

Executing modules as scripts

Add to the file mymodule.py:

pi = 3.141592653589793

def x2(x):
  return x*x

def degtorad(t):
  return pi/180.*t

if __name__ == "__main__":
  import sys
  print(x2(float(sys.argv[1])))

now, you can execute it:

$ python mymodule.py 4
16

or import it:

>>> import mymodule

Where does python find modules ?

  • in the local directory
  • in the directories listed in the environement variable PYTHONPATHH
  • in the python directory

Standard modules

Standard modules are module that comes with the python distribution. They are described in the Python Library Reference : https://docs.python.org/3/library/index.html

Some examples:

>>> import sys        # System-specific parameters and functions
>>> import os         # Miscellaneous operating system interfaces
>>> import glob       # Unix style pathname pattern expansion
>>> import shutil     # High-level file operations
>>> import time       # Time access and conversions
>>> import math       # Mathematical functions

>>> sys.argv[1]
>>> sys.exit()

>>> os.mkdir('test')
>>> os.chdir('test')
>>> os.getcwd()

>>> open('file1','w')
>>> os.symlink('file1','file2')
>>> os.mkdir('directory')

>>> glob.glob('*')
>>> os.listdir('.')

>>> os.path.isfile('file1')
>>> os.path.isfile('file2')
>>> os.path.isfile('file3')

>>> os.path.isfile('directory')
>>> os.path.isdir('directory')

>>> os.remove('file1')
>>> os.remove('directory')
>>> os.removedirs('directory')

>>> os.chdir('../')

>>> shutil.rmtree('test')

>>> time.time()

>>> math.pi
>>> math.sqrt(2)

Classes

Classes (objects) provide a means of bundling data and functionality together. Class instances can have attribute attached to them (kind of variables). Some of those variables called methods corresponds to functions that can modify the state of the class instance.

Define a new class

an empty minimal class::
>>> class Spacecraft:
...   pass
...
>>> type(Spacecraft)
<class 'type'>
>>> Spacecraft
<class '__main__.Spacecraft'>
>>>

a more elaborate class

define the class and add a method to it:

>>> class Spacecraft:
...   pos=0
...   def Info(self):
...     print("I am a spacecraft")

create a new instance columbia (local variable) of the class Spacecraft:

>>> columbia = Spacecraft()
>>> columbia.pos
0
>>> columbia.Info()
I am a spacecraft
>>>

A method to customized to a specific initial state of the instance:

>>> class Spacecraft:
...   def __init__(self):
...     self.pos = 0
...   def Info(self):
...     print("I am a spacecraft")
...     print("My current position is {}".format(self.pos))

the same with optional arguments:

>>> class Spacecraft:
...   def __init__(self,pos=0):
...     self.pos = pos
...   def Info(self):
...     print("I am a spacecraft")
...     print("My current position is {}".format(self.pos))

>>> columbia = Spacecraft(pos=10)
>>> columbia.Info()
I am a spacecraft
My current position is 10

adding methods:

>>> class Spacecraft:
...   def __init__(self,pos=0,vel=0,acc=0,dt=0):
...     self.pos = float(pos)
...     self.vel = float(vel)
...     self.acc = float(acc)
...     self.dt  = float(dt)
...   def Info(self):
...     print("I am a spacecraft")
...     print("My current position is {}".format(self.pos))
...
...   def Drift(self):
...     self.pos = self.pos + self.dt * self.vel
...
...   def Kick(self):
...     self.vel = self.vel + self.dt * self.acc
...

>>> columbia = Spacecraft(pos=0,vel=1,dt=0.1)
>>> columbia.Drift()
>>> columbia.Drift()
>>> columbia.Drift()
>>> columbia.Info()
I am a spacecraft
My current position is 0.30000000000000004

a compleete example:

>>> class Spacecraft:
...   def __init__(self,pos=0,vel=0,acc=0,dt=0):
...     self.pos = float(pos)
...     self.vel = float(vel)
...     self.acc = float(acc)
...     self.dt  = float(dt)
...   def Info(self):
...     print("I am a spacecraft")
...     print("My current position is {}".format(self.pos))
...   def Drift(self):
...     self.pos = self.pos + self.dt * self.vel
...   def Kick(self):
...     self.vel = self.vel + self.dt * self.acc
...   def Integrate(self,tmax):
...     t=0
...     while (t<tmax):
...       print("t={:6.3f} pos={:6.3f} vel={:6.3f} acc={:6.3f}".format(t,self.pos,self.vel,self.acc))
...       self.Kick()
...       self.Drift()
...       t = t + self.dt


>>> columbia = Spacecraft(pos=0,acc=1,dt=0.1)
>>> columbia.Integrate(5)
t= 0.000 pos= 0.000 vel= 0.000 acc= 1.000
t= 0.100 pos= 0.010 vel= 0.100 acc= 1.000
t= 0.200 pos= 0.030 vel= 0.200 acc= 1.000
t= 0.300 pos= 0.060 vel= 0.300 acc= 1.000
t= 0.400 pos= 0.100 vel= 0.400 acc= 1.000
t= 0.500 pos= 0.150 vel= 0.500 acc= 1.000
t= 0.600 pos= 0.210 vel= 0.600 acc= 1.000
t= 0.700 pos= 0.280 vel= 0.700 acc= 1.000
t= 0.800 pos= 0.360 vel= 0.800 acc= 1.000
t= 0.900 pos= 0.450 vel= 0.900 acc= 1.000
t= 1.000 pos= 0.550 vel= 1.000 acc= 1.000
t= 1.100 pos= 0.660 vel= 1.100 acc= 1.000
t= 1.200 pos= 0.780 vel= 1.200 acc= 1.000
t= 1.300 pos= 0.910 vel= 1.300 acc= 1.000
t= 1.400 pos= 1.050 vel= 1.400 acc= 1.000
t= 1.500 pos= 1.200 vel= 1.500 acc= 1.000
t= 1.600 pos= 1.360 vel= 1.600 acc= 1.000
t= 1.700 pos= 1.530 vel= 1.700 acc= 1.000
t= 1.800 pos= 1.710 vel= 1.800 acc= 1.000
t= 1.900 pos= 1.900 vel= 1.900 acc= 1.000
t= 2.000 pos= 2.100 vel= 2.000 acc= 1.000
t= 2.100 pos= 2.310 vel= 2.100 acc= 1.000
t= 2.200 pos= 2.530 vel= 2.200 acc= 1.000
t= 2.300 pos= 2.760 vel= 2.300 acc= 1.000
t= 2.400 pos= 3.000 vel= 2.400 acc= 1.000
t= 2.500 pos= 3.250 vel= 2.500 acc= 1.000
t= 2.600 pos= 3.510 vel= 2.600 acc= 1.000
t= 2.700 pos= 3.780 vel= 2.700 acc= 1.000
t= 2.800 pos= 4.060 vel= 2.800 acc= 1.000
t= 2.900 pos= 4.350 vel= 2.900 acc= 1.000
t= 3.000 pos= 4.650 vel= 3.000 acc= 1.000
t= 3.100 pos= 4.960 vel= 3.100 acc= 1.000
t= 3.200 pos= 5.280 vel= 3.200 acc= 1.000
t= 3.300 pos= 5.610 vel= 3.300 acc= 1.000
t= 3.400 pos= 5.950 vel= 3.400 acc= 1.000
t= 3.500 pos= 6.300 vel= 3.500 acc= 1.000
t= 3.600 pos= 6.660 vel= 3.600 acc= 1.000
t= 3.700 pos= 7.030 vel= 3.700 acc= 1.000
t= 3.800 pos= 7.410 vel= 3.800 acc= 1.000
t= 3.900 pos= 7.800 vel= 3.900 acc= 1.000
t= 4.000 pos= 8.200 vel= 4.000 acc= 1.000
t= 4.100 pos= 8.610 vel= 4.100 acc= 1.000
t= 4.200 pos= 9.030 vel= 4.200 acc= 1.000
t= 4.300 pos= 9.460 vel= 4.300 acc= 1.000
t= 4.400 pos= 9.900 vel= 4.400 acc= 1.000
t= 4.500 pos=10.350 vel= 4.500 acc= 1.000
t= 4.600 pos=10.810 vel= 4.600 acc= 1.000
t= 4.700 pos=11.280 vel= 4.700 acc= 1.000
t= 4.800 pos=11.760 vel= 4.800 acc= 1.000
t= 4.900 pos=12.250 vel= 4.900 acc= 1.000
t= 5.000 pos=12.750 vel= 5.000 acc= 1.000

A final puzzeling example:

>>> class C:
...   l = []
...   def __init__(self):
...     pass
...   def add(self,o):
...     self.l.append(o)

>>> c1 = C()
>>> c2 = C()
>>> c1.add(1)
>>> c1.l
[1]
>>> c2.l
[1]
>>> c2.add(2)
>>> c2.l
[1, 2]
>>> c1.l
[1, 2]

Documenting Python

Create a module spacecraft.py

"""
This file contains the definition of the spacecraft class
"""

class Spacecraft:
  """
  This is my spacecraft class
  """

  def __init__(self,pos=0,vel=0,acc=0,dt=0):
    """
    Initialize the instance
    """
    self.pos = float(pos)
    self.vel = float(vel)
    self.acc = float(acc)
    self.dt  = float(dt)

  def Info(self):
    """
    Return some info.
    """
    print("I am a spacecraft")
    print("My current position is {}".format(self.pos))

  def Drift(self):
    """
    Drift the spacecraft (x = x + dt*v)
    """
    self.pos = self.pos + self.dt * self.vel

  def Kick(self):
    """
    Kick the spacecraft (v = v + dt*a)
    """
    self.vel = self.vel + self.dt * self.acc

  def Integrate(self,tmax):
    """
    Integrate the equation of motion during tmax
    """
    t=0
    while (t<tmax):
      print("t={:6.3f} pos={:6.3f} vel={:6.3f} acc={:6.3f}".format(t,self.pos,self.vel,self.acc))
      self.Kick()
      self.Drift()
      t = t + self.dt

Retrieve help:

>>> import spacecraft
>>> help(spacecraft)

This gives:

Help on module spacecraft:

NAME
    spacecraft - This file contains the definition of the spacecraft class

CLASSES
    builtins.object
        Spacecraft

    class Spacecraft(builtins.object)
     |  This is my spacecraft class
     |
     |  Methods defined here:
     |
     |  Drift(self)
     |      Drift the spacecraft (x = x + dt*v)
     |
     |  Info(self)
     |      Return some info.
     |
     |  Integrate(self, tmax)
     |      Integrate the equation of motion during tmax
     |
     |  Kick(self)
     |      Kick the spacecraft (v = v + dt*a)
     |
     |  __init__(self, pos=0, vel=0, acc=0, dt=0)
     |      Initialize the instance
     |
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |
     |  __dict__
     |      dictionary for instance variables (if defined)
     |
     |  __weakref__
     |      list of weak references to the object (if defined)

FILE
    /home/revaz/ownCloud/Lectures/Python/Doc/spacecraft.py

Other important topics not covered in this tutorial

  • Errors and Exceptions
  • Packages
  • Extending python with C