## Short explanation of Python

[ambient page updated 11 Oct 05] ... [ home ] ... [ garrett@math.umn.edu ]
```
At the unix prompt, type "python" (and hit return) and you'll get the
python prompt:

>>>

To _stop_ python and return to the unix prompt, type "Control-D" at
the python prompt.

If python gets stuck in a loop or in a too-long process, "Control-C"
interrupts it and returns you to the prompt.

In its simplest use, the python prompt gives a read-evaluate-print
loop, which has many built-in functions useful for basic computational
number theory. Addition is +, multiplication is *, division is /,
substraction is -, use of parentheses is as usual. A slightly less
standard use is ** for exponentiation, so, for example, 2**5=32. The
python prompt's loop can be used as a simple calculator, by entering
an expression and hitting "return" to evaluate it:

>>> 2*3
6
>>> 4 * 4
16
>>> 2**10
1024
>>> (3+5) * (1+2)
24
>>>

Whitespace between operators doesn't matter.

An unusual feature of python is that it has built-in
infinite-precision integers, of arbitrary size. These are denoted by
appending an "L" to the numeral. If the numbers get too large for
ordinary integers, you'll get an overflow error:

>>> 2 ** 100
Traceback (innermost last):
File "", line 1, in ?
OverflowError: integer pow()
>>>

But if you use "long" integers it'll be fine:

>>> 2L ** 100
1267650600228229401496703205376L
>>>

Of course, you can still ask the machine to do tedious and stupid
things, such as

>>> 2L ** 1000000

##  If you do this, for example, the machine will appear to hang. If
##  you realize that you've made a stupid request, you _can_ stop it
##  in the middle without harming anything: do Control-C, and you'll
##  be returned to the prompt.

For use in crypto and other computational number theory, there is a
built-in function which does _modular_exponentiation_: to compute

x^e % m    (x to the e power reduced modulo m)

do _not_ do

>>> (x**e) % m                ## bad!

>>> pow(x,e,m)                ## good

The latter uses a smart algorithm. So, for example, ridiculously large
exponents are ok (as long as the "L" suffix is used):

>>> pow(2L, 10L**100+1, 10L**100+1)
6660888126245688699182136543775795641628347778449324704651411345556300289268422357122875536174966145L

takes an imperceptible amount of time to evaluate. Very good.

#################################################################
#################################################################

There are built-in mathematical functions, too, but preparation for
them requires _importing_ the "math module": do

>>> import math

just once at the beginning of a python session, to import the math
module. Thereafter, the following functions and constants (among
others) are available:

math.log10( )     ## log base 10
math.pi           ## 3.14159265359
math.sqrt( )      ## square root, in floating-point: watch out!
math.acos( )      ## inverse cosine
math.sin( )       ## sine function, in radians
math.atan2(,)     ## = arctan( firstargument / secondargument )
math.exp( )       ## exponentiation base e
math.asin( )      ## arcsine
math.floor( )     ## greatest integer less-than-or-equal-to: the floor function
math.fabs( )      ## least integer greater-than-or-equal-to: the ceiling function
math.log( )       ## natural log
math.e            ## 2.71828182846
math.atan( )      ## arctangent

The usage as set up here requires the prefix "math", as in

>>> math.log10(2)
0.301029995664
>>>

On hazard is that these functions only keep a fixed number of decimal
places of "precision", so

######################################################################

To _replay_ and _edit_ the last command, a nice subset of EMACS
text-editing capabilities is available: among other things, a basic
set of commands is

("C-x" is an abbreviation for "Control-x")
("M-x" is an abbreviation for "Meta-x")

C-f           ;; move forward by one character
C-b           ;; move backward by one character
M-f           ;; move forward by one word
M-b           ;; move backward by one word

C-p           ;; recall previous command (can be iterated further!)
C-n           ;; move to next command

C-a           ;; move to beginning of line
C-e           ;; move to end of line

C-d   ;; delete next character
M-d   ;; delete next word

DEL           ;; delete previous character
M-DEL         ;; delete previous word

C-k           ;; delete from point to end of line

The arrow keys usually work, also.

######################################################################

A related organizational tool (as well as actualy programming
capability) is the possibility of _named_variables_. This can be done
at the python command line loop, using "=" to assign values to
variables.

>>> n = 1001
>>> n
1001
>>> n = n+1
>>> n
1002
>>>

This allows more coherent treatment of complicated expressions:
>>> n =1001
>>> n
1001
>>> n = n+1
>>> n
1002
>>> n = 1000001L
>>> n
1000001L
>>> a = pow(2,n,n)
>>> a
210991L
>>>

######################################################################

"While loops" are easy to write:

>>> i=1
>>> while i<10:      ## hit return at end of line
...     print `i`    ## hit tab at beginning of line, return at end
...     i = i+1      ## hit tab at beginning of line, return at end
1
2
3
4
5
6
7
8
9
>>>

Note that the backquotes convert _numbers_ to _strings_

Note that braces are _not_ used. Rather, code blocks are indicated by
_indentation_. Thus, every line in the "while block" must be indented,
conventionally by a tab. Sub-blocks have their own further
indentation:

>>> i = 1                ## hit return
>>> j = 1                ## hit return
>>> while i<5:           ## hit return
...     while j <= i:    ## tab at beginning, return at end of line
...             print `i+j`   ## _two_ tabs at beginning, return at end
...             j = j+1     ## _two_ tabs at beginning, return at end
...     i = i+1             ## _one_ tab at beginning, return at end
...	                      ## just a return, to close the outer block
2
4
6
8
>>>

######################################################################

"For loops" are similar, and also "if/else" statements are reasonable:

>>> n = 1000001
>>> n % 3
2
>>> n = 1000001
>>> for i in range(1,1001):
...     if n % i == 0:
...             print `i`
...
1
101
>>>

The syntax of the "else" clause is:

Note that the _test_ for equality (as opposed to _assignment_ of
variable values) is a _double_ equal sign.

The "range" thingy tells the variable i to assume all integer values
including the bottom but excluding the top value. It has an optional
argument that tells how much to increment it (the default is 1):

>>> for i in range(1,10,3):
...     print `i`
...
1
4
7
>>>

If the range is rather large, it may be more economical to use a
variant construct "xrange", rather than plain "range", which does not
create the whole list in memory at one time:

>>> for i in xrange(1,100000):
...     if i== 12345:
...            print `i`
...	  elif i== 1234501:
...			   print "Hello"
...	  else:
...				pass
12345
'Hello'
>>>

This example also showed how to print a string. It also showed how to
have a "no-operation" occur: the keyword is "pass"

######################################################################

It is easy to define simple functions to use in the python
command-line loop, using "def" and "return" keywords:

>>> def f(x):                       ## hit return
...     return x*x*x-3*x*x+17*x-1   ## hit tab at beginning of line, return at end
>>> f(1)
14
>>> f(0)
-1
>>> f(-1)
-22
>>> f(2)
29
>>>

Somewhat more complicated things can also be set up in code blocks,
using "if/else" blocks and "for" or "while" loops:

>>> def f(n):
...     if n == 1:
...             return 1
...     elif n==2:
...             return 2
...     else:
...             return 3
...
>>> f(4)
3
>>>

Variable names and function names can be long and descriptive if you
want:

>>> def primality_test(n):
...     bound = int( math.sqrt(n) )
...     for i in range(3,bound+1,2):
...             if n % i == 0:
...                     return `i` + " divides " + `n`
...     return `n` + " is prime "
...
>>> primality_test(101)
'101 is prime '
>>> primality_test(105)
'3 divides 105'
>>>

Note that the "+" operator also concatenates _strings_, which can be
delimited by double-quotes.

######################################################################

_List_ syntax is reasonable:

>>> mylist = [1,2,3]
>>> mylist
[1, 2, 3]
>>> mylist.append(101)
>>> mylist
[1, 2, 3, 101]
>>> mylist.append(123)
>>> mylist
[1, 2, 3, 101, 123]
>>> mylist

Lists can be used in _for_loops_:

>>> for i in mylist:
...     print `i`
...
1
2
3
101
123
>>>

Here's the time to point out a variant form of _print_, which doesn't
insert a newline after each item, but only a space:

>>> for i in mylist:
...     print `i`,
...
1 2 3 101 123
>>>

That is, the comma after the `i` causes the "print" to only insert a
space rather than newline.

The length of a list is accessible by the "len" function, which also
can compute the length of a _string_:

>>> len(mylist)
5
>>> len("hello")
5
>>>

The various elements of a list are accessible by typical index
notation, with indices beginning at 0:

>>> mylist
3
>>> mylist
1
>>>

_Slices_ of lists use a funny but reasonable notation

>>> mylist[0:3]
[1, 2, 3]
>>> mylist[:-1]
[1, 2, 3, 101]
>>> mylist[:-2]
[1, 2, 3]
>>> mylist[0:-2]
[1, 2, 3]
>>> mylist[1:-2]
[2, 3]
>>> mylist[2:-2]

>>> mylist[3:-2]
[]
>>> myslice = mylist[3:]
>>> myslice
[101, 123]
>>>

######################################################################

When you get tired of retyping at the command-line loop, you can (of
course) put python code into files and _either_ "run" such files on
their own, _or_ use them as "modules" from the python command-line
loop itself.

To load into the command loop files defining
functions/subroutines/methods, these files should end with ".py", like
"myfile.py", _and_ should either be in your current directory (in a
unix sense), or in your python module search path. (At the unix prompt
do "echo \$PYTHONPATH" to see the value of this environmental
variable.)

Suppose that myfile.py contains just the two lines (ended by a newline!)

def f(n):
return n+1

(Assuming that the python interpreter can find the files, because
they're in the search path), to load myfile.py into the python loop,
do

>>> import myfile

Note that the suffix is not included. Then functions defined in myfile
can be called by

>>> myfile.f(5)
6

If the definition of myfile.f is changed in myfile.py and you want to

To load functions/methods in a manner so that the prefix "myfile." is
not needed, use the syntax

>>> from myfile import f
>>> f(11)
12
>>>

Such Python modules can include auxiliary functions called
internally. Such internal use does not require use of the prefix
naming the module. For example, myfile.py might contain the 3 lines
(with newline at the end)

import math
def mysqrt(n):
return math.sqrt(n)

Then