******************************************************************************* PYTHON 2.x VERSUS 3.x In Python 3 some minor design mistakes of earlier versions have been corrected. Programs written for earlier versions will not run in Python3 but they can be converted using an automated tool 2to3. See www.python.org Just one of the differences between the two versions concerns printing. 2.x print "hello" 3.x print("hello") This document concerns Python 3.x. ******************************************************************************* PYTHON INTERPRETER AND ON-LINE HELP The interactive Python interpreter allows you to try snippets of code, execute application files, and obtain on-line help. To invoke the interactive Python interpreter type at the shell prompt: idle3 To exit the Python interpreter press ctrl-d or type exit() Notice that Python is case sensitive. In Python everything is an object; even a type such as str. ("abc" is an object of type str; str is an object of type type). For any OBJECT you can use: help(OBJECT) dir(OBJECT) # attributes and methods of OBJECT For instance: help(str) help(str.strip) To explore the help utility, type: help() In the interactive interpreter the underscore _ is a variable that always stores the last printed expression. To use the interactive interpreter as a scientific calculator, execute: from math import * import math help(math) A definitive version of on-line documentation can be found at www.python.org ******************************************************************************* TWO KINDS OF PYTHON SCRIPTS A Python source code file is also called - a Python script file, or - a Python module. Python scripts can be edited using any text editor or by using IDLE (Integrated DeveLopment Environment for Python). On UNIX/Linux systems with X-windows you can invoke IDLE by typing in the shell: idle3 Idle's editor will perform color-coding and will balance parentheses; many editors, including emacs, gedit, kate can be configured to do the same. There are two kinds of Python scripts: - An APPLIACTION executable from the Linux shell prompt, OR - A LIBRARY MODULE importable into other Python scripts or into IDLE ******************************************************************************* PYTHON APPLICATION FILES An application file under Unix/Linux: 1. Should be made executable, with the UNIX command: chmod u+x FILE 2. The first line in the file, with no preceding tabs or spaces, must be: #!/usr/bin/env python3 3. The file does not need an extension, but may have extension .py or any other extension. A recommended style under Linux is not to have any extension. Whenever you run a Python application file in the Linux shell it is run by the Python interpreter. To run an application in the shell type the file name. To run an application in IDLE3 type the following at the Python prompt. def load(): exec(open("FILENAME","rb").read()) Then, every time you need to execute the program enter: load() ******************************************************************************* USING PYTHON LIBRARY MODULES To use a library module MODULE.py in another Python file or in IDLE3 import MODULE where MODULE is the module file name without the extension .py Notice that any executable code in the module is executed when the module is imported the first time, but not if it is imported subsequently; if you need to execute it again (for testing changes), use: import imp imp.reload(MODULE) Variables, functions, etc. from the imported module can be accessed using the dot notation MODULE.VARIABLE, MODULE.FUNCTION(...), etc. ******************************************************************************* WRITING PYTHON LIBRARY MODULES A library module file: 1. Does not need to be executable; 2. Does not need the first line such as #!/usr/bin/env python3 3. Must have extension .py It is easiest to place your library modules in the same directory as the application that uses them. It is possible to create a file which is both an application and a library module by combining the requirements above. This is done to provide in the same file a library module and a function that tests it. If the testing function is main(), include at the end of the file: if __name__ == "__main__": main() Then import the module whenever you wish to use it, and whenever you want to test it, just run it from the Linux shell. ******************************************************************************* COMMENTS AND DOCSTRINGS The symbol # begins a comment which ends with the closest following newline character. The # does not need to be the first character on the line. The first line in application files #!/usr/bin/python ... is NOT a regular comment; that line tells the shell to invoke /usr/bin/python to execute the script. At the beginning of any module, function, class or method you can place a string, in any Python-allowed syntax, without assigning it to a variable. This string does not affect the execution of the module or function but it provides documentation which can be accessed at run-time by accessing OBJECT.__doc__ Docstrings are used to automatically generate documentation for a module. (Write libary module with doc strings, import it into IDLE3 and call help on the module.) For instance >>> def square(x): ... '''A unary function that takes a number and returns its square.''' ... return x*x ... >>> print(square.__doc__) A unary function that takes a number and returns its square. >>> help(square) ... ******************************************************************************* NEWLINES Python statements do not require a semicolon at the end. Only if you wish to put more than one statement per line, then you need need separate them with semicolons. If a statement is to long to fit on a single line you can break it into two or more lines but every newline except last must be escaped by a backslash. The code between matching ( and ), [ and ], { and }, ''' and ''', or """ and """ can span many lines which do not end with backslashes; (notice that (), [], {} are used in function calls, indexing, slicing, tuple, list and dict literals, etc.) ******************************************************************************* EXPRESSIONS Expressions and statements are two different syntactic categories. An expression evaluates to a value, while a statement performs an action. For instance 2+x and (2+x)*5 are expressions while the following is a statement: if x>0: print(x*x) print(2*x) Expressions are built from variables and literals using operators (such as +) and parentheses (for grouping). Combining expressions (of an appropriate type) by means of an operator results in an expression. Languages such as C and Java blur the distinction between expressions and statements by allowing expressions with side-effects: Expr Value Side-effect (action) x++ the value of x x gets the value of x+1 ++x the value of x+1 x gets the value of x+1 x=e the value of e x gets the value of e (also side-effects of e) x+=e the value of x+e x gets the value of x+e (also side-effects of e) etc. In Python: ++ and -- operators are not available; =, =+, etc. form statements, not expressions. To see that x = 3 is not a Python expression, try to execute y = (x = 3) in the interactive interpreter -- this will cause an error. In Python arithmetical expressions do not have side-effects: evaluating an arithmetical expression does not change values of variables. ******************************************************************************* SPACES AND TABS Recommended indentation is 4 spaces. Do not use tabs because different editors display them with a differnt width. Invoke python with -t option to get warnings about tabs in a file. If you got a pyhton file which uses tabs, you can eliminte them using a unix command "expand" $ mv FILE.py FILE.old.py $ expand FILE.old.py > FILE.py This replaces every tab by 8 spaces. If you want a differnt number, see $ expand --help ******************************************************************************* SUITES A "block of statements" or a "compound statement" is used to group a number of statements together. For instance here is a block of two statements which are executed together depending on a condition. if i > 0: x = i**2 y = x + i In other programing languages blocks of statements are surrounded by curly braces or pairs of keywords "begin" and "end". In Python no such delimiters are used; a block of statements is defined by equal indentation of its statements. This implies that (unlike in other programming languages) use of space characte rs is not arbitrary. Here is an example of properly indented Python code. while i > 0: if i % 2 == 0: x = i ** 2 y = x + i i -= 1 In the Python terminology blocks are called "suites". Python statements which need to be followed by a suite end with a colon, e.g.: for VARIABLE in ITERABLE: SUITE def FUNCTION(PARAMETERS): SUITE Suites cannot be nested (unlike blocks in other programming languages); the following will cause an error: x = 1 y = x x = 2 print(x, y) print(x) Suites may introduce variables, but unlike in other programming languages, the scope of such a variable is not limited to the suite. The scope of a variable can be more than its suite: 1 if True: 2 x = 0 3 x += 1 # This is in the scope of the variable on line 2. but does not have to: 1 if False: 2 y = 0 3 y += 1 # Error: y undefined. More about the scope in section SCOPE. ******************************************************************************* STYLE - use 4 spaces for indentation, no tabs; - wrap lines so that they are not longer than 79 characters; - separate function definitions and class definitions with a blank line or separator such as #-------------- - use docstrings; - put spaces around operators and after a comma: y = (2 + x) * f(1, 2); - capitalize class names; - use lowercase for variables and function and method names. - use UPPERCASE for constants (i.e. variables meant not to change). - for private data use indentifiers whose names begin with one underscore (they will not be reported in the automatically generated on-line information) - structure the program file as follows: module docstring import statements global constants (variables which do not change) global variable declarations and initializations class declarations function declarations body (code to be exceuted when the file is executed or loaded) - it is recommended to place all the executable code in a function main and have at the bottom of the file a call to main. ******************************************************************************* VARIABLES AND CONSTANTS In Python and many scripting languages (unlike in C and Java) variables do not have declarations preceding statements which use them: if you need a variable you just start using it. Variables do not have types but objects do: you can assign an integer to a variable x and then assign to it a string. x = 10 x = "abc" There are no constants. (You can even reassign math.pi=7 -- silly) Programmers can use variables as constants and make sure the program does not change their values. UPPERCASE is recommended for names of such variables. A Python variable stores a reference to an object, never the object itself. ******************************************************************************* TYPING Python's typing has the following characteristics: Strong typing, in the sense that: - every object has a unique type, that does not change throughout its lifetime, - coercion (implicit type conversion) is limited to numbers: 10>20.3 is legal, but 10 > "123" is not legal, - run-time type safety: operations on wrong types will not be performed (for instance 10 + "123" will cause an error.) Implicit typing (i.e. non-manifest typing): - you do not declare a variable to be of any specific type. Dynamic typing: - objects have types but variables don't (the variable name is bound to an object but not to a type) - you can store in the same variable first an object of one type then an object of a different type. Duck typing: - The definition of function/method/operation does not restrict it to any specific types, instead, the function/method/operation will be applicable to all objects with a specific API (the methods the object supports). ******************************************************************************* ASSIGNMENT STATEMENTS Assignments can be chained: EXPRESSION0 = EXPRESSION1 EXPRESSION0 = EXPRESSION1 = EXPRESSION2 etc. AUGMENTED ASSIGNMENT STATEMENTS use the following symbols +=, -=, *=, /=, //=, %=, **= (Arithmetical) >>=, <<=, &=, ^=, |= (Bitwise) For instance: x += 1 Chaining augmented assignments is not allowed: x = y += 1 is illegal ******************************************************************************* CONDITIONALS if TEST: BLOCK elif TEST2: BLOCK2 elif TEST3: BLOCK3 else: BLOCK4 There can be any number of elif-clauses; the else-clause is optional. There is no case/switch statement. ******************************************************************************* LOOPS for VAR/TUPLE in ITERABLE: SUITE for i in range(5): print(i) x = i*i print(x) for c in "abcd": print(c) for i, c in enumerate("abcd"): # i- index, c-character print(i, c) while TEST: SUITE There are no other loops. Within any loop one can use statements: continue break typically in a conditional. continue immediately starts a new iteration; break immediately terminates the loop. ******************************************************************************* OUTPUT print can take arbitrary objects as arguments, not just strings. (every object has an __str__ method which returns a string describing the object; the print function looks for that string.) In Python 3.x print is a function, so it requires parentheses around the parameter list. print("hello\n", "world!") This actually is: print(value, ..., sep=' ', end='\n', file=sys.stdout) and will separate consecutive values by a space, print newline at the end and use standard output, but we could provide other values for named parameters to change the behavior. print("abc", end='') # without \n, a flush is needed: sys.stdout.flush() ******************************************************************************* INPUT n = int(input(PROMPTSTRING)) Notice that the inner call returns a string without a newline; int converts it to an integer. Similarly, you could use conversions: float, complex and eval(STRING) to convert an appropriate STRING to an object such as list or dict. ******************************************************************************* OBJECTS Everything (!) is an object. Numbers are objects. Functions are objects. Classes are objects. Types are objects. Modules are objects, etc. Every object has a type which will not change during the life of the object: type(OBJECT) Although 22 and "22" are of different types, namely int and str, both [22, 22] and ["22", "22"] are of the same type, namely list; so as far as types go there is no distinction between a list of integers and a list of strings -- a list of any objects is of the same type: list. A type determines the operations supported defines the possible values for objects of that type and determines the operations supported by these objects. There is an object None which serves purposes similar to those of Null or nil in other languages. Identity of objects (sameness of memory location) can be tested with x is y x is not y They are fast. Equality of objects can be tested with x == y x != y These test recursively the structure of the objects. They can be slow for big objects. Notice that if x is y is true then x==y is true but not conversely; also if x!=y is true then x is not y is true, but not conversely. Every object has a unique id during its lifetime. id(OBJECT) Notice that: x is y iff id(x)=id(y) You can think about id as a memory address (but Python specification does not require such an implementation.) EXAMPLE >>> x = 7000 >>> y = 7000 >>> z = x >>> x == y True >>> x == z True >>> x is y False >>> x is z True To delete a reference to an object use del x after the last reference is deleted, the object is eligible for automatic garbage collection. Representations of an object as strings (!): str(OBJECT) # for humans repr(OBJECT) # for the Python interpreter To create an object from a Python string representation use eval(STRING) Notice that: eval(repr(OBJECT))==OBJECT for ALMOST any object. print actually prints str(OBJECT) or in its absence repr(OBJECT). Class names can be called without parameters to construct a default object: int() # returns 0, or with a parameter to convert the parameter to an object of that class (if feasible) int(3.7) # returns 3 This is very useful if you need to convert a list to a tuple, etc. In some cases more parameters are allowed. OPTIONAL READING: EXCEPTIONS TO THE RULE "A LITERAL CONSTRUCTS A NEW OBJECT" WITH NUMBERS >>> x = 1000 >>> y = 1000 >>> x is y False >>> # As explained before. >>> x = 1 >>> y = 1 >>> x is y True >>> # Inconsistent with the Python principles, but for implementation efficiency. WITH TUPLES (immutable sequences of arbirary objects) >>> t1 = (1, 2) >>> t2 = (1, 2) >>> t1 is t2 False >>> # As explained before. >>> t1 == t2 True >>> t1 = () >>> t2 = () >>> t1 is t2 True >>> # Is it consistent with the Python principles? ******************************************************************************* ASSIGNMENT VS. SHALLOW COPY VS. DEEP COPY To copy an arbitrary object do import copy x = copy.copy(OBJECT) # shallow copy y = copy.deepcopy(OBJECT) Some classes, for instance set and dictionary, provide their own shallow copy: s = {1,2,3} x = s.copy() y = set.copy(s) # the same as the line above. -------------- ASSIGNMENT performs a copy of the reference. >>> x = [[1000, 2000], [3000, 4000]] >>> y = x >>> x == y True >>> x is y True x and y refer to the same object; Changing x DOES affect y (and vice versa): >>> x[0] = 5000 >>> x [5000, [3000, 4000]] >>> y [5000, [3000, 4000]] --------- SHALLOW COPY copies only the top level structure but not its components. >>> import copy >>> x = [[1000, 2000], [3000, 4000]] >>> y = copy.copy(x) >>> x == y True >>> x is y False >>> x[0] is y[0] True Changing the top level structure in x does NOT affect y (and vice versa): >>> x[0] = 5000 >>> x [5000, [3000, 4000]] >>> y [[1000, 2000], [3000, 4000]] Changing the lower level structures in x DOES affect y (and vice versa): >>> x = [[1000, 2000], [3000, 4000]] >>> y = copy.copy(x) >>> x[1][1] = 7000 >>> x [[1000, 2000], [3000, 7000]] >>> y [[1000, 2000], [3000, 7000]] -------------- DEEP COPY copies all levels of the structure >>> x = [[1000, 2000], [3000, 4000]] >>> y = copy.deepcopy(x) >>> x == y True >>> x is y False >>> x[0] is y[0] False Changing any part of the structure, even the lower level structures in x, does NOT affect y (and vice versa): >>> x[0][0] = 7000 >>> x [[7000, 2000], [3000, 4000]] >>> y [[1000, 2000], [3000, 4000]] -------------- We can start from two copies of an object created from literals (this is like deep copy, however copy.deepcopy can do the same evan during runtime): >>> x = [[1000, 2000], [3000, 4000]] >>> y = [[1000, 2000], [3000, 4000]] >>> x == y True >>> x is y False >>> x[0] is y[0] False x and y do not share any part of their structures; Changing any part of the structure, even the lower level structures in x, does NOT affect y (and vice versa): >>> x[1][1] = 7000 >>> x [[1000, 2000], [3000, 7000]] >>> y [[1000, 2000], [3000, 4000]] ******************************************************************************* FUNCTIONS We distinguish between FUNCTION DEFINITIONS and FUNCTION CALLS. Here is a definition of a function: >>> def double(x): ... y = x*2 ... return y Here are some calls to this function: >>> m = double(3) >>> m = double(m) >>> s = double("abc") If no return statement is executed in the function body then on normal termination the function returns value None. fuction printHeader(n): print("Welcome to the calculator (version ", n, ")." Put function definitions before the calls. Recall that parameters present in the header of function definition are called FORMAL PARAMETERS; Parameters present in a function call are called ACTUAL PARAMETERS; For instance, for the function double above, x is a formal parameter, y is a local variable, and 3, m and "abc" are actual paramaters. Parameters in Python are passed BY VALUE i.e. a copy of the actual parameter is made and stored in the formal parameter; and the function operates on that copy. Keep in mind that in Python everything is an object and is accessed via a reference, so when a function starts executing it makes copies of references given as actual parameters, but not copies of the objects they refer to. This mneans that the fucntion will operate on the same objects the actual parameters refer to. Variables used in the body of a function definition are local to the function unless the body contains one of the statements: global VARIABLE nonlocal VARIABLE in which case, VARIABLE refers to the global (file scope) variable of that name or the variable of that name in whose scope this function definition resides. A definition of a function can contain definitions of other functions; they will be local to the enclosing function. It is possible to define functions with named parameters, with optional parameters, with default values of parameters and taking an arbitrary number of parameters. More about parameters in section MUTABLE VERSUS IMMUTABLE. ******************************************************************************* NUMBERS The following types are built in: integer, float, complex More in modules: fractions, decimal. All numbers are immutable objects. One can create two different integer objects with the same value however only for "big" integers; for "small" integers Python does not do that for efficiency reasons. The range of integers is unlimited (except by the size of computer memory). Integer literals are typed using the usual notation. To convert to an integer use the function int(...) this can convert any number, other than complex, or any string which looks like an number to an integer. The floats have a limited range and precision (they are identical to the type double in C). Float literals are typed using the usual notation with the decimal point and/or exponent in the scientific notation: -23.45 -23.45E-3 -23E5 To convert to a float use the function float(...) This will convert any number, other than complex, or any string which looks like a number to a float. Complex number literals are typed as realPart + or - imaginaryPart j or J where the realPart and imaginaryPart are integers or floats. For instance, 2+3.0j 20.01E4-0.03J To convert to a complex number use the function complex(...) This will convert any number or a string which looks like a number to a complex number. Operations on numbers (in order of precedence): ** (exponentiation) -, + (unary) *, /, % +, - (binary) Notice that ++ and -- are not available. For integer arguments / always returns a float. To perform integer division use // ; this returns the floor: -4//3 returns -2. Comparison operators ==, != work for arbitrary objects, not just numbers. >, >=, <, <= work for any numbers other then complex. The math module provides additional operations (trigonometric functions, etc); Cmath does the same for complex numbers. ******************************************************************************* BOOLEANS Use: True, False, and, or, not True and False are immutable. There is only one True object and there is only one False object. The following objects represent the truth-value false: - False - 0, 0.0, 0+0j (zeros) - "", (), [], set(), frozenset(), {} (empty containers) - None All other objects are converted to True unless the programmer specifies otherwise. In a context where a number is expected True is automatically converted to 1 and False to 0. ******************************************************************************* SEQUENCES A sequence is any container object which - supports element access via the __getitem__() method with integer indices starting at 0, and - supports __len__() method that returns its length. SEQUENCE[INDEX] is equivalent to SEQUENCE.__getitem__(INDEX) len(SEQUENCE) is equivalent to SEQUENCE.__len__() The following sequences are available in the language or standard library. str 'abc' or "abc" or '''abc''' or """abc""" consist of one-letter-strings (there is no character type) immutable bytearray sequence of 8-bit unsigned integers mutable bytes sequence of 8-bit unsigned integers immutable list ['a', 3, [3,'c'], d] consist of arbitrary objects mutable tuple ('a', 3, (3,'c'), d), () -- the empty tuple, (12,) -- a one element tuple requires a comma, 1,2,3 -- same as (1,2,3), because (12) would be just a parenthesized number; consists of arbitrary objects, immutable, collections.namedtuple like a tuple but values can be also accessed by a field name (like in a record) range range([START,] END [,STEP]) immutable These ranges do not support slices, +, +=, *, *=, <, >, <=, >=; they support == and != . Most sequences available in the language or in the standard library support the following constructs. Additional constructs may be available for specific types of sequences. len(SEQUENCE) returns length SEQUENCE[INDEX] evaluates to the value stored in the sequence at the index INDEX; valid indices are 0,1,2,...,LENGTH-1 (from the left end) and -1, -2, -3,...,-LENGTH (from the right end); INDEX must be valid; otherwise IndexError is raised. MUTABLESEQUENCE[INDEX] = VALUE stores VALUE at an existing INDEX. The index must be valid; otherwise IndexError is raised SEQUENCE[START:END] where START, END are arbitrary (!) integers; if START is not given (but colon is present) this means: from the beginning; if END is not given (but colon is present) this means: to the very end; evaluates to a sequence which is a slice that excludes (!) SEQUENCE[END]; with mutable sequences this can be used even on the left side of assignment. SEQUENCE[START:END:STEP] where START, END, STEP are arbitrary (!) integers, or are not given, however STEP !=0; if STEP is not given it defaults to 1; evaluates to a sequence which is a strided slice; with mutable sequences this can be used even on the left side of assignment. SEQUENCE[:] evaluates to a shallow copy of SEQUENCE (a copy that contains the same ! items.) SEQUENCE[::-1] evaluates to the sequence of the same (!) items in reverse order. >>> x=[[1],[2],[3]] >>> y=x[::-1] >>> y [[3], [2], [1]] >>> x[0][0]=0 >>> y [[3], [2], [0]] MUTABLESEQUENCE.append(OBJECT) modifies MUTABLESEQUENCE adding OBJECT at the right end. MUTABLESEQUENCE.extend(SEQUENCE) modifies MUTABLESEQUENCE adding all components of SEQUENCE on the right. for example: [1, 2, 3].extend("abc") produces [1, 2, 3, a, b, c]. SEQUENCE1 + SEQUENCE2 The sequences must be of the same type; evaluates to the concatenation of the two sequences. (Members of the result are also members of the original sequences. SEQUENCE1 += SEQUENCE2 The sequences must be of the same type (except that LIST+=ITERABLE is OK.) If SEQUENCE1 is mutable, it will be modified; otherwise a new sequence will be created. SEQUENCE * INTEGER evaluates to a concatenation of a number of shallow copies of the sequence. (All members of the result are also members of the original sequence.) SEQUENCE *= INTEGER evaluates to a concatenation of a number of shallow copies of the sequence; (All members of the result are also members of the original sequence.) If SEQUENCE is mutable, it will be modified; otherwise a new sequence will be created. SEQUENCE.count(OBJECT) returns the number of occurrences of OBJECT in SEQUENCE sorted(SEQUENCE) returns a sorted list (!) of items from SEQUENCE keeping duplicates; The full specs: sorted(ITERABLE, key=None, reverse=False) where key is a function applicable to the items in ITERABLE SEQUENCE1 < SEQUENCE2 both must be of the same type; returns True if they are in lexicographic order. >, <=, >= similar to <. ==, != work for any objects not just sequences. ------ Sequence conversions. string to a tuple: tuple("abc") list to a tuple: tuple([1,2,3]) tuple to a list: list([1,2,3]) string to a list: list("abc") tuple of one character strings to a string: "".join(("a","b","c")) list of one character strings to a string: "".join(["a","b","c"]) ******************************************************************************* STRING SUBSTITUTION print("%s bbb %s" % ("aaa", "ccc")) This substitutes the members of a tuple for the occurrences of %s. ******************************************************************************* MUTABLE VERSUS IMMUTABLE >>> a = [1, 2, 3] >>> for item in a: ... item *= 2 ... print(item) ... 2 4 6 >>> print(a) [1, 2, 3] # The list above is unchanged because numbers are immutable. >>> b = [[1], [2], [3]] >>> for item in b: ... item[0] *= 2 ... print(item) ... [2] [4] [6] >>> print(b) [[2], [4], [6]] # The list items have changed! ------------------------------------------------------------------------ Tuples are immutable but their components can be mutable: >>> a = [2, 3] >>> b = (1, a, 4) >>> b (1, [2, 3], 4) >>> a[0] = 0 >>> b (1, [0, 3], 4) Note: if a mutable object is stored in a tuple, and we change the value of that object, the change also affects the tuple. >>> a = (1,[2,3],4) >>> a[1][0]=5 >>> a (1, [5, 3], 4) ------------------------------------------------------------------------ The effect of += subtly depends on mutability of LHS (left-hand side). >>> a = b = (0, 1) >>> a += (2, 3) >>> a (0, 1, 2, 3) >>> b (0, 1) >>> a = b = [0, 1] >>> a += [2, 3] >>> a [0, 1, 2, 3] >>> b [0, 1, 2, 3] Also, for a mutable object on the left, x+=y is not the same as x=x+y: >>> a = b = [0, 1] >>> a = a + [2, 3] >>> a [0, 1, 2, 3] >>> b [0, 1] ------------------------------------------------------------------------ The following example shows that immutable actual parameters (such as integers) are not changed by the function call. >>> def f1(x): ... x = 5 ... return x ... >>> a = 1 >>> f1(a) 5 >>> a 1 Mutable parameters can be changed by a function call >>> def f2(x): ... x[0] = 5 ... return x ... >>> a = [1] >>> f2(a) [5] >>> a [5] ******************************************************************************* HASHABLE OBJECTS An object can be used as a key in dictionaries or an element of sets iff the object is hashable iff the object is unchangeable (it is an immutable object with immutable components at all levels). hash(OBJECT) returns a hash code if OBJECT is hashable, otherwise it raises an exception. The concept of mutability/immutability refers to types; The concept of hashability refers to objects: the type tuple is immutable but not all tuple objects are hashable: the tuple ([1],[2]) is not hashable because it has mutable components. All objects constructed using just numbers, Booleans, None and tuples are hashable. >>> d={1:11, 2:22} >>> hash(d) Traceback (most recent call last): File "", line 1, in TypeError: unhashable type: 'dict' ******************************************************************************* DICTIONARIES These are known in programming as tables, hashes, association lists, associative arrays. At some level of abstraction dictionaries are similar to arrays: arrays store values indexed by integers (0..n); dictionaries store values indexed by strings called keys. # Create an empty dictionary >>> d1 = {} # insert into d1 the value ("tom","518 564 2788") # corresponding to the key "smith" >>> d1['smith'] = ('tom', '518 564 2788') # See what is in d1 >>> print(d1) {'smith': ('tom', '518 564 2788')} >>> # or >>> for key in d1: ... print(key, d1[key]) smith ('tom', '518 564 2788') # Check if 'smith' is a key in d1 >>> 'smith' in d1 True # Update the value corresponding to the key "smith" >>> d1['smith'] = ('peter', '566 8999') >>> d1 {'smith': ('peter', '566 8999')} >>> # Notice that there cannot be two different values with the same key. # delete the entry whose key is "smith" >>> del d1['smith'] >>> d1 {} # Delete all entries from d1 (which will still exist as an empty dict) >>> d1.clear() # Delete dictionary d1 >>> del d1 Process all keys: for k in DICTIONARY: print(k) or for k in DICTIONARY.keys(): print(k) Process all items (i.e. key-value pairs): for i in DICTIONARY.items(): print(i) Process all values: for v in DICTIONARY.values(): print(v) DICTIONARY.items(), DICTIONARY.keys(), DICTIONARY.values() return "dictionary views"; They are read-only iterables which change dynamically when DICTIONARY changes. Python 3.x has also collections.OrderedDict An ordered dictionary is both a mapping object and a sequence which maintains the order in which the pair with a given key was first inserted . ******************************************************************************* SAVING AND RESTORING A DATA STRUCTURE USING A FILE mydict = {1:[2,3], 4:[5,6]} myfile = open('data.dat','w') # creates file if it does not exist; # destroys contents if file exists myfile.write(repr(mydict)) myfile.close() myfile = open('data.dat','r') mydict = eval(myfile.read()) # read() returns a string, # eval() converts it to another object. myfile.close() ******************************************************************************* ASSIGNMENT, TUPLE/LIST PACKING, SEQUENCE UNPACKING >>> (a, b, c) = (1, 2, 3) >>> print(a, b, c) 1 2 3 >>> a, b, c = 1, 2, 3 >>> print(a, b, c) 1 2 3 >>> (x, x)=(1, 2) >>> x 2 In general the following work: TUPLE = SEQUENCE LIST = SEQUENCE but the LHS AND RHS must be of the same length. For instance [a, b, c] = range(3) # RHS cannot contain uninstantiated variables. # Python's assignment is not a unification. >>> del x >>> [x, y] = [1, x] Traceback (most recent call last): File "", line 1, in NameError: name 'x' is not defined >>> (x, y) = (1, x) Traceback (most recent call last): File "", line 1, in NameError: name 'x' is not defined ******************************************************************************* SCOPE Python uses lexical scoping (static scoping). Here is a classic example of such a scoping. >>> def givex(): ... return x ... >>> def f(): ... x = "abc" ... return givex() ... >>> x = 0 >>> print(f()) 0 >>> x = 1 >>> print(f()) 1 ------------------------------------------------------------------------- The following examples concern using local/non-local variables. >>> x = 0 >>> def f(): ... x += 1 ... >>> f() Traceback (most recent call last): File "", line 1, in File "", line 2, in f UnboundLocalError: local variable 'x' referenced before assignment So, non-local variable not declared as such cannot be used as LHS. >>> x = 0 >>> def g(): ... print(x) # non-local x >>> g() 0 So, a non-local variable not declared as such can be used as RHS. >>> x = 0 >>> def h(): ... x = 1 # local x ... return x >>> h() 1 >>> x 0 >>> x = 0 >>> def i(): ... global x ... x = 1 ... return x >>> i() 1 >>> x 1 ******************************************************************************* NAMESPACES >>> class Namespace: pass >>> n = Namespace() >>> n.a = 5 >>> n.f = lambda x : x**2 >>> n.a = n.f(n.a) >>> print(n.a, n.__dict__) # doctest: +ELLIPSIS 25 {'a': 25, 'f': at ...>} ******************************************************************************* Python examples can in a text file can be tested as follows. - invoke python3 interpreter and type: import doctest doctest.testfile("python-intro.txt") - type at the shell prompt: python3 -m doctest python-intro.txt | head -n 24 *******************************************************************************