Intro to Python


Python is..

Simple, powerful, FUN..

PS: It is 'Python' as in 'Monty Python', not 'python the snake' :)

List of topics

This is an almost-complete list of items:

  • what/why of Python
  • installing and running Python - various shells
  • basic calculations
  • comments
  • variables, types [incl type changing, var deleting]
  • clean syntax
  • dir(), type(), help()
  • strings
  • basic data structures: lists, tuples, dictionaries
  • operators
  • flow control
  • functions [unique return type], classes
  • modules (eg. os, sys, math, random, re etc.), packages
  • misc: eval(), file-handling
  • functional aspects


NOT covered in detail:

  • error handling
  • classes (object-oriented type construction)
  • functional programming
  • writing modules in other languages (eg. C++)
  • ...


# when you see code like this (in a gray box), you can
'''
copy (ctrl c) and paste (ctrl v)
it into the script-editor window.
'''

A compact introduction to Python

Below is a set of 'topics' to explore sequentially - together, they will give you an introductory view of Python.

Be sure to type in and execute all the code you see, don't just look at it onscreen! Typing it in and watching it run (or not) is the first-hand way to learn, it's what 'sticks'.

Python philosophy

Quote: Python is a freely available, very high-level, interpreted language developed by Guido van Rossum. It combines a clear syntax with powerful (but optional) object-oriented semantics. Python is widely available and highly portable.

Summary: Python is *simple*, yet *powerful*. Elimination of visual clutter, adhering to consistency and useful shorthand for common tasks provides this refreshing combination. For comparison, BASIC is simple but not powerful; C++ is powerful and is in no way 'simple'!

Also, Python comes with so many modules (libraries, ie. separate, bundled code) for doing everything under the sun - 'regular expressions' to UI creation to webservers to graphics to games to data acquisition - all ready to use right out of the box, in identical ways! Hence the expression "Python comes with batteries included".

Python shells

Python is interpreted, so the best way to learn it is to interactively type commands into a Python shell. Choices for the Python shell:

Calculations

Python can be used as a simple 'calculator',to add, subtract, multiply, divide and do exponentiation (even with BIG numbers).

Type the following (and everything else!) into Maya's 'Python' tab, select what you typed (just like with MEL), and hit Enter at the right of the keyboard (again, just like with MEL). Maya will run the Python code inside its embedded interpreter, and provide you feedback above the Script Editor window (once again, just like with MEL).

Note - get into the good habit right away, of first selecting text to run, then using the rightmost 'Enter' key to execute it.

2+5

0.2

8*4.5

a = 2
b = 3
area = a*b
area
peri= 2*(a+b)
peri

Delete names:

del(a)
del(b)
del(peri)
del(area)
area # this name is not defined anymore

7/3 # integer division!

7/-3

7.0/3

7.0/-3

7.0/3

7.0//3 # floored int div, ie integer quotient

float(7)

int (7.0)

float(7)/3

int(float(7))/3 # big noop with int() and float()

int(float(7))/3.0

int(float(7))/int(3.0) # bigger noop


# modulus (excess, or remainder):
45.67%3.2
# remove the excess, divide again, to get exact quotient
(45.67 - (45.67%3.2)) / 3.2
# int quotient, float reminder both in one step:
divmod(7.666,1.0)


pow(2,4) # or 2**4
2**400
13*457 # !!
import math # for math calculations, we need the math "module"
math.sin(1.5)
from math import * # so we don't need to prefix 'math.'
sin(1.57)

dir()
dir(__builtins__)
dir(math)

'Python' ' is ' 'fun' # strings placed next to each other are auto. concatenated

raw_input("Enter a number: ") # raw_input always returns a string

int(raw_input("Enter a number: ")) # int() casts a valid 'intable' string to int

Dynamic, yet strong typing

No need to declare variables' types during creation - Python infers types. Variables stay bound to their types until they're reassigned to new types.

Also, multiple, mixed-type assignments are possible in the same statement,

a = 45 # implicitly, a is declared an int
type(a)

b = 12.0
type(b)

a/b # floating point /

s = a/b # s is now a float
s[0] # not a string
type(s)

s = "Python is fun" # now it is
s[0] # Each char is a string

a,b,c = 45, 3.1415,'Wow' # a,b,c created all at once, each is a diff. type!


c = 3+4j # complex # type is built in
type(c)

c.real

c.imag

d = 1+2j

c*d # complex number mult :)

c.conjugate()

c = c.conjugate()
c
# again:
c = c.conjugate()
c

c*c.conjugate() # if c=a+ib, this is (a**2+b**2)

pow((c*c.conjugate()).real,.5) # magnitude

abs(c) # simpler way!

c = complex(3,4) # constructor

complex(3,0)

complex(3) # imag. is 0

(0.5+0.8j)**0.5

((0.5+0.8j)**0.5)**2 # :)

More on numeric types: http://python.about.com/od/pythonstandardlibrary/a/numeric_types.htm

Comments

There are two styles of commenting..

# this is a one liner comment
'''This
comments
spans several
lines'''

No pointers/refs

Every name in Python is a ref. to an object, there are no explicit pointers/refs for the user to manipulate.

Printing
print "Complex c's value is",c # expressions, separated by commas

or use:

format % values

'values' needs to be a "list". A single element of such a list does not need to be in parantheses, but multiple items DO (see below).

a=10
b=45
print "a and b are %d and %d" % (a,b) # two items to print, specified using ( )

c = 3+4j
print "complex number c is %s" % repr(c) # just one item to print, the ( ) is optional
print "complex number c is %s" % (repr(c)) # exact same result as prev. line

d = 5 + 6j
print "c and d are %r, %r" % (repr(c),repr(d)) # two items, specified as a list

%d, %f, %r, %s etc. are 'format specifiers'. repr() is a function that returns a string representation of a non-string (eg. complex) type.

Indentation

Part of the syntax!!!!!!!!!!

Each new level of indentation starts a new *block*; these can be nested.

a = 25
 print a # error!
print a # works

Data types, structures

Built-in types:

  • boolean
  • int, long int (eg. do 2**1024), double prec. float
  • complex
  • string
  • sequences (WORKHORSES of Python!!!):tuple, list (*the* hardest working horse of all!), dictionary

path
import sys
print "PYTHONPATH is ",sys.path # list of dirs.

help
help()

help>modules

help>keywords

help>topics

help(5)

help(1+2j)

# HTML help!
# note: 'Tcl' needs to be installed for this to work
import pydoc
pydoc.gui()

Let's explore some more, the 'string' data type, and lists-tuples-dictionaries.

string

s = "Python is a wonderful language"

len(s) # counts chars


dir(s) 
dir("")

s.count('a')
s.index('t')

s.split() 

# what if we had "Python:is:a:wonderful:language"? 
"Python:is:a:wonderful:language".split()
"Python:is:a:wonderful:language".split(':')

s = 'python is fun'
s.capitalize()

s.upper()
s.lower()


# join joins elements of a list 
'-.-'.join(['A','a','z','Z'])

# + concatenates
'Hawa' + 'ii'



list

l = ['a', 'Test', 'magic']

len(l)

l.reverse()

# again
l.reverse()

l.append('wow')
l.insert(2,'this')

l.remove('a')
l.remove(l[2])

l.insert(3,last)
l.sort()

tuple

t = ('a', 'Test', 'magic')

t.reverse()
t.append('HEY!!')

dir(t) # we discover that tuples are 'read-only', ie 'immutable'

dictionary

tel = {'saty':'5-6713', 'gigi':'5-6714'}

type(tel)

dir(tel) # or dir({})

len(tel)

print tel['gigi']

tel.keys()
tel.values()

tel.has_key('val')

tel['val'] = '5-3543'

del tel['saty']
tel

Flow control: if, while, for [and also break, continue, pass]

These constructs (if, while, for) serve as building blocks for branching and looping.

if
a,b = 10,2
# usual comparison ops: ==, !=, <, >, <=, >=
a==b
a!=b

# for two tests, use 'and', 'or' to join; 'not' negates a single test
a!=b and b==1
a!=b or b!=2

a = 12
b = 25
if a>b:
  print a
elif a==b:
  print "a and b are both equal to %d" % a
else:
  print b
# elif and else are both independently optional

c = -5
d = 5

if a<b and c<d:
  print a
else:
  print b

elif avoids deep nested blocks like the following. It takes the place of switch() in C/C++/..

if a>b:
  print "a>b"
else:
  if a==b:
    print "a==b"
  else:
    if a==100:
      print "a is 100"

# cleaner
if a>b:
  print "a>b"
elif a==b:
  print "a==b"
elif a==100:
  print "a is 100"

while
import random
random.seed(45)
running = True
while running:
  r = random.random()
  print r
  if r>0.5:
    running = False
else: # this is optional (should have been called 'after'!)
  print "end of while()"


random.seed(450)
# try above loop again..

Fibonacci sequence:

a,b=0,1 # :)
while b<10000:
  a,b=b,a+b
  print b, float(b)/a 
# qn: what is the limit of b/a?

Note that in the above, we did multiple assignments in the same statement. These can even be done to vars of different types!

a,b = 5, "Test"

a,b = b,a # !!!!

a,b,c,d = 1,2,3,4
print a,b,c,d

a,b,c,d = b,c,d,a
print a,b,c,d

for
for i in range(1,10): # iterates NINE times, not 10
  print random.random()

range(6,12) # generates a LIST: [6, 7, 8, 9, 10, 11] 

count=0
for i in range(1,100):
  r = random.random()
  if r<0.5:
    print r
    count = count+1
else: # optional
  print "printed %d values" % count

break, continue, pass

'break' breaks out of an immediate while or for loop, before loop condition becomes false - it is an 'early' exit. When a 'break' occurs, an else: block that is present will *not* get executed.

'continue' skips rest of a loop block, to return control to the top, to start a new iteration.

'pass' is simply a no-op 'filler' statement (it means "do nothing").

a = True
while a==True:
  s = raw_input('Enter something: ')
  if s=="done" or s=="exit" or s=="quit":
    print "all done, 'break'ing"
    break
  if len(s)>5:
    print "input too long - try again"
    continue
  print "You entered ",s
  a = False
else:
  print "End of while() loop"
pass

# infinite loop!
while True:
  pass # NEED this no-op stmt. to create a valid block - eqvt to while(1){} in C/C++

dir(), type()

type(), dir(), len() etc. are examples of built-in functions.

'dir' lists names in the current module or in a named module.

dir()

import math
dir(math)

dir(__builtins__) # "built in" functions, exceptions, attrs

'type()' returns an object's type.

d=56
type(d)

d='Test'
type(d)

type(5)

type({})

type([]}

type(4+6j)

The above material was a brief introduction to Python. Here are more topics that you do need to explore, to round out your knowledge: lists, tuples and dictionaries, modules, classes and functions, "Pythonisms" (eg. list comprehension), built-in modules, file handling, documentation, exceptions, math, recursion, reflection, UI, modules for CG and math..

To use Maya-related commands, use the 'maya.cmds' module.

import maya.cmds # our 'hook' into the world of Maya!!!

a = dir(maya.cmds)
for i in range(len(a)):
  print a[i]

maya.cmds.sphere() # equivalent to MEL's 'sphere()'

Maya - UI creation

Here is an example of UI creation. We use the same window, layout, widgets, showWindow sequence as we did in MEL, but now in Python syntax.

# here is a common 'as' idiom, to save some typing
# (maya.cmds.() can simply be mc.())

# select a bunch of nodes, then run the following

import maya.cmds as mc


def createMyLayout( obj, parent ):
    mc.setParent(parent)
    c = mc.columnLayout()
    text = mc.textField(text=obj)
    button1 = mc.button(label="one")
    button2 = mc.button(label="two")
   
    return c

myLayouts = []
w = mc.window("example", title="Sample UI creation")
c = mc.columnLayout()
for selectedObject in mc.ls(sl=True):
    myLayouts.append(createMyLayout(selectedObject, c))
mc.showWindow(w)

Functions, classes!

As we saw above, a function is defined using 'def', and is called (after defining) just like in MEL.

def sind(x):
  import math
  return math.sin(x*math.pi/180)

In the above, we're recreating MEL's useful sind() function. The 'def' keyword starts off the fn defn; next is the function's name, then comes the arg list (just like in MEL - but HUGE diff - only var names, NO TYPES!). In the body of the fn, one or more 'return' calls return values..

Once a fn has been defined, use it (call it) just like in MEL..

sind(45)
  
for i in range(90):
  print sind(i)

A huge benefit/feature: a fn can return a tuple!!!!!!

The above means that a Python fn can be written to output possibly MULTIPLE items, of possibly MULTIPLE types! This is a huge no-no in other languages, so programmers use sneaky techniques to get around this. In Python, we'll output multiples openly and with blessings :)

# returns a hodgepodge type of 7 items, as a tuple, in a single return call!!
def howCool():
  return (1,0.56,(),[5,"Test",5-3j],[],7.45,[[]])
  
# this alone is worth switching to Python :) 
a,b,c,d,e,f,g = howCool()
a
b
c
d
e
f
g
g[0] 
g[0][0] # not defined, so will generate an error


Python functions can recurse:

def fact(n):
  if n==1:
    print "End of recursion, returning 1"
    return 1
  else:
    print "Recursing: returning",n,"*","fact(",n-1,")"
    return n*fact(n-1)
    
fact(45) #!!!!!

Try fact(105)!! FYI it has 169 digits, which means they can be arranged like so (1+3+5+7+9+11+13+15+17+19+21+23+25=169):

                                        1                        
	                               081                      
	         	              39675                    
	        	             8240290                  
	       	                    900504101                
		                   30580032964              
	    	                  9720646107774            
    		                 902579144176636          
    		                57322653190990515        
  		               3326984536526808240      
 	 	              339776398934872029657    
	 	             99387290781343681609728  
		            0000000000000000000000000

For more on 105!, see http://webdocs.cs.ualberta.ca/~smillie/APE/APE43.html

Classes are used to group together related variables and functions into a useful unit. Once created, a class can be instantiated into an object, whose methods can be get/set and functions invoked. Objects can communicate with each other by calling functions on them. The class/object mechanism is the way to create custom types.

Here is a basic example, to give you a taste. Overall idea - define a class (with a name, acting as a container), place fns inside it, create "objects" (instances, ie rubber stamps, of the class), call fns as usual, but call them as 'object.function_name'.

class A:
  '''Class A, with two methods f1 and f2'''
  def f1(self): # note the 'self' keyword
    print "Running A.f1()"
  def f2(self):
    print "Running A.f2()"


a = A() # a is now a variable (object) of type (class) A

type(A)
type(a)

A
a

dir(A)
dir(a)


A.__doc__
A.__module__


a.f1() # invoke a's f1() method

# error - no need to (can't) pass in 'self' - that keyword is valid only 
# inside a class def.
a.f1(self) 

a.f2()

modules

As mentioned earlier, modules are 'add-ons' (plugins, in a sense) to Python - they extend Python's functionality via new classes and/or functions. Each module has a name, which we need to use, to start invoking all the functionality residing in the module.

For example, how do we do math calculations (not + - * / ^ %, but more, such as sin(), log(), sqrt() etc.)? This doesn't seem to work:

x = 45
y = sin(x)
y = sqrt(x)

This is because sqrt() and sin() and many other math functions (and constants 'pi' and 'e') are defined in a 'math module', which is NOT loaded by default when Python starts up - we need to import the module's functionality if/when we need it:

import math
x = 45
print math.sin(x)
print math.sqrt(x)

All module functionality is accessed via a simple pattern, which is modulename.functionality, ie, by using the module's name as a prefix, it's that easy!

How do we know what functionality a module has? Read the doc (via a web page, help() function etc), or, use dir():

dir(math) # list all of the math module's names, ie. vars, functions

We see that cos() etc. are also present in 'math':

# Result: ['__doc__', '__name__', '__package__', 'acos', 'acosh', 'asin', 
'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 
'degrees', 'e', 'exp', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum',
'hypot', 'isinf', 'isnan', 'ldexp', 'log', 'log10', 'log1p', 'modf', 'pi', 
'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc'] # 

Where can/should modules (which can be .py, or .dll) be kept, for Python to be able to find them when we do an import? Use a module called 'sys' to find out:

import sys
sys.path # THESE dirs are where Python will look, when you ask it to 'import' a module

Every user-written .py script/text file is automatically a module!!. To see this, create a text filed called mymodule.py in one of the dirs from the searchpath above, and type this in:

print "Hi world"

Save the file, then do this in the Script-Ed window (Python tab of course):

import mymodule

Voila! You see that 'Hi world' gets output - Python loaded the module, and ran the commands (just one right now) in it. Cool!

Add two more lines to mymodule.py, save:

print "Hi world"

import math
print math.sqrt(49)

Re-import the module. NOTHING gets printed, not even the first print statement! This is because Python will only load (from disk) a module once, via 'import'. Extra import commands are ignored. BUT we need it to reload! So - use 'reload' instead:

reload(mymodule)

NOW it works! Lesson: when you make changes to module code, be sure to reload() it right after, to force Python to pick up the changes.

Let's get help() on our module:

help(mymodule)
Help on module mymodule:

NAME
    mymodule

FILE
    c:\users\dad\documents\maya\scripts\mymodule.py

Not much there. Help on math() says more:

help(math)
Help on built-in module math:

NAME
    math

FILE
    (built-in)

DESCRIPTION
    This module is always available.  It provides access to the
    mathematical functions defined by the C standard.

FUNCTIONS
...

Where did all that text come from? THE MODULE WRITER put those in!! Python makes it VERY EASY to document a module and its code (classes, methods, standalone functions). The mechanism used is called a 'docstring', which is triple-quoted comment block at the beginning of a module, class, method or function.

Let's add a docstring to mymodule.py:

'''
This is our own module, to put in ANY functionality we like!
This help line can
  span
   several
    lines.
'''

print "Hi world"

import math
print math.sqrt(49)
reload(mymodule)
help(mymodule)

We get:

reload(mymodule)
Hi world
7.0
# Result:  # 
help(mymodule)
Help on module mymodule:

NAME
    mymodule

FILE
    c:\users\dad\documents\maya\scripts\mymodule.py

DESCRIPTION
    This is our own module, to put in ANY functionality we like!
    This help line can
      span
       several
        lines.

Now we're talking :)

FYI, the docstring for a module is stored in a specially named variable (called __doc__ - notice the TWO leading and trailing underscores) of that module:

mymodule.__doc__
# Result: 
This is our own module, to put in ANY functionality we like!
This help line can
  span
   several
    lines.
 # 

Let's add a small function, and document it:

'''
This is our own module, to put in ANY functionality we like!
This help line can
  span
   several
    lines.
'''

print "Hi world"

import math
print math.sqrt(49)

def geomMean(a,b):
'''Finds the geometric mean, sqrt(a*b), of inputs a,b'''
 return math.sqrt(a*b)
# geomMean

Let's do help() on the module, and also, exercise our brand new function:

reload(mymodule)
help(mymodule)

mymodule.geomMean(1,64)

We get:

Hi world
7.0
Help on module mymodule:

NAME
    mymodule

FILE
    c:\users\dad\documents\maya\scripts\mymodule.py

DESCRIPTION
    This is our own module, to put in ANY functionality we like!
    This help line can
      span
       several
        lines.

FUNCTIONS
    geomMean(a, b)
        Finds the geometric mean, sqrt(a*b), of inputs a,b

mymodule.geomMean(1,64)
# Result: 8.0 # 

There are HUNDREDS of modules (possibly thousands) out there, many are free to download and use! This is why Python rocks - so much functionality, so easy to get and put to use.

Here are some commonly used modules (learn more about them after this course): math, random, re, os, sys, numpy.

There are at least 5 different syntax variations, when it comes to modules and specific classes inside them:

import random # base syntax, eg. to say random.gauss(5,.2)
import random as rnd # so we can say rnd.gauss() instead of random.gaussian()
from random import gauss # just say gauss(), no need for a prefix
from random import gauss as gs # to be able to say gs() 
from random import * # to leave out the prefix in ALL calls - not a good idea (why not?)

packages

The Maya 'site-packages' directory contains packages, plus paths to all sorts of packages elsewhere.

What are packages? They are collections of modules!

import maya # 'maya' is a package, contains maya.cmds module and others..

dir(maya) # lists all the modules in the package
dir(maya.cmds) # lists contents of the maya.cmds module

help(maya)
help(maya.cmds)

import os

dir(os)

help(os)
help(os.path)

# prints out an actual expanded filename, ie, in this case, where the 'maya' package is located
print os.path.dirname(maya.__file__)

misc topics

eval()

eval() is powerful (and potentially dangerous) - it can execute any piece of Python code!

eval(  "math.sqrt(81)"  )

It takes a string as input, and returns an output based on whatever the Python code the string happens to contain!! Among other things, this means we can ask the user the input such a string, to pass on to eval:

# raw_input() is a Python call that waits for user input
# it always returns a string
userInput = raw_input("Type in a function, eg. math.sin(x), or math.sqrt(x) etc.: y = ")

# now we pass the string in userInput, to eval
for x in range(1,101):
  print "x = ", x , ", y = ", eval(userInput)

Eg. try typing these in (one at a time of course), to raw_input() above:

math.sqrt(x)

(math.sin(x))**2+(math.cos(x))**2

math.log10(x)

files

Python lets you read, write and append to text (ASCII) as well as binary files.

Here's how to read in a text file (create it first!), and print it out line by line:

fIn = open("C:/temp/test.txt",'r')
type(fIn)
dir(fIn)
lines = fIn.readlines()
type(lines)
for l in lines:
    print l

You can print it all out, in just one line of code, like so:

open("C:/temp/test.txt").read()

# the entire file comes out of open() as a single string:
type(open("C:/temp/test.txt").read())

Lists, map(), "list comprehension"

l = [] # an empty list, fillable (unlike a tuple!)
l.append(1)
l.append('test')
l
l.__contains__(7)
l.__contains__('test')

l[1]
len(l)


# print each elemnt in a list
for a in l:
  print a

# roundabout:
for a in range(len(l)):
  print l[a]

l.append([]) # empty list is appended to our list
l

l[2].append('r')
l # can insert elements into a list's list element!
for i in range(10):
  l[2].append('r')
l

l[2] = {} # last list element is replaced with {}
l

del(l[1])
l

m = l + [1,2,3,9,8,7] # + concatenates lists
m
m += m

map() is a function used to iterate a function over a list or several lists. Output is a list of the function's results.

# iterate sind() for each el in range(0,360)
# replaces the for() version shown earlier!
snf = map(sind,range(0,360)) 
snf
# qn: above prints the list in a single line - how would you print
# each item in a separate line?

'List comprehension' is an alternate way to do this kind of function looping (over a range of inputs), esp. for simpler functions. Example:

li = [1,3,5,7]
li
[item*2 for item in li]
li = [item*2 for item in li] # input (li) is a list, so is the output!
li

We can safely overwrite a list variable with its processed version (which is copied to the variable AFTER getting fully formed in memory).

Q. Where is list comprehension useful?

A. provides a useful shortcut for this common pattern:

for item in list
  if condition on item
   process item, accumulate for output

The 'list comprehension' version is

[expr for item in li if condition]

Example: li = [1,2,3,4,5,6,7,8,9,10] li = [x*x for x in li if x%2 == 0] li # prints [4, 16, 36, 64, 100]

In the above, the input is a list, so is the output, which is a PROCESSED VERSION of the input list!

In summary - following are 3 eqvt ways to create this list: [0,0.1,0.2..0.9]

#1. use a for() loop
l = []
for i in range(10):
 l.append(float(i)/10)

#2. define a function, then pass it to map()
def decimalify(x):
  return float(i)/10.0

l = map(decimalify, range(10))

#3. use 'list comprehension'
l = [decimalify(i) for i in range(10)] # optionally, *can* have an if 

List comprehension and map() are two instances of 'functional programming' in Python. There are three more - look them up if you are interested: lambda ('anonymous function'), reduce(), filter().