a tour of python

42
Aleksandar Veselinovic 2012.

Upload: aleksandar-veselinovic

Post on 22-Jan-2017

291 views

Category:

Software


2 download

TRANSCRIPT

Page 1: A tour of Python

Aleksandar Veselinovic

2012.

Page 2: A tour of Python

OVERVIEW• Introduction

• Syntax

• Types and objects

• Operators and expressions

• Structure and control flow

• Functions and functional programming

• Classes and OOP

• Modules, packages, and distribution

• Input and output

• Execution environment

• Testing, debugging, profiling and tuning

Page 4: A tour of Python

PYTHON INTERPRETER

PythonCPython

Jython

Python for .NET

IronPython

PyPy

Python is defined “by implementation”. CPython is default Python.

CPython is a bytecode interpreter. It has a foreign function interface with several languages including C, in which one must explicitly write bindings in a language other than Python.

Page 5: A tour of Python

DATA MODEL

Type hierarchy

None

NotImplemented

Ellipsis

Numbers

numbers.Integral

Plain integers

Long integers

Booleans

numbers.Real

numbers.Complex

Sequences

Immutable

Mutable

Strings

Unicode

Tuples

Lists

Byte arrays

SetsMutable

Immutable

Set

Frozen setMappingsDictionaries

Callable

User defined functions

User defined methods

Generator functions

Built-in functions

Built-in methods

Class types

Classic classes

Class instances

Modules

ClassesClass instances

Files

Internal types

Code objects

Frame objects

Traceback objects

Slice objects

Static method objects

Class method objects

Page 6: A tour of Python

OPERATIONS

Operations Numeric

Integer

intBoolean subtype

32 bits+

Unlimited precision long

Operations

x | y

x ^ y

x & y

x << n

x >> n

~x

x + y

x - y

x * y

x // y

x % y

-x

+x

abs(x)

int(x)

long(x)

complex(re, im)

z.conjugate()

divmod(x, y)

powerpow(x, y)

x ** y

complexz.real

z.imagAdditional methods

numbers.Real

math.trunc()

round(x[, n])

math.floor(x)

math.ceil(x)

For floats only

float.as_integer_ratio()

float.is_integer()

float.hex()

float.fromhex()

numbers.Integralint.bit_length()

long.bit_length()

Sequence

x in s

x not in s

s + t

s * n, n * s

s[i]

s[i:j]

s[i:j:k]

len(s)

min(s)

max(s)

s.index(i)

s.count(i)

Page 7: A tour of Python

COMPARISONS

Truth value testingTrue False

Zero

0

0L

0.0

0j

Empty sequence

''

()

[]

Empty mapping {}

User defined classes__nonzero__()

__len__()

None

Boolean operations

and

or

not

Comparisons

Sequence typesin

not in

Class instances__cmp__() All objects

<

<=

>

>=

==

!=

Object identityis

is not

Page 8: A tour of Python

BUILT-IN FUNCTIONS

• Refrain from using names that hide built in functions. Common errors: id, min, max.

• If you are using vim add to your .vimrc:let python_highlight_builtins=1

Page 9: A tour of Python

LISTS AND TUPLES>>> a = [66.25, 333, 333, 1, 1234.5]>>> print a.count(333), a.count(66.25), a.count('x')2 1 0>>> a.insert(2, -1)>>> a.append(333)>>> a[66.25, 333, -1, 333, 1, 1234.5, 333]>>> a.remove(333)>>> a[66.25, -1, 333, 1, 1234.5, 333]>>> a.reverse()>>> a[333, 1234.5, 1, 333, -1, 66.25]>>> a.sort()>>> a[-1, 1, 66.25, 333, 333, 1234.5]>>> squares = []>>> for x in range(10):... squares.append(x**2)...>>> squares[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]>>> squares = [x**2 for x in range(10)]>>>>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y][(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]>>> combs = []>>> for x in [1,2,3]:... for y in [3,1,4]:... if x != y:... combs.append((x, y))...>>> combs[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

>>> t = 12345, 54321, 'hello!'>>> t[0]12345>>> t(12345, 54321, 'hello!')>>> # Tuples may be nested:... u = t, (1, 2, 3, 4, 5)>>> u((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))>>> # Tuples are immutable:... t[0] = 88888Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: 'tuple' object does not support item assignment>>> # but they can contain mutable objects:... v = ([1, 2, 3], [3, 2, 1])>>> v([1, 2, 3], [3, 2, 1])

List comprehension!

>>> import itertools>>> import pprint>>> pprint.pprint(list(itertools.permutations("spam")))

Page 10: A tour of Python

SETS>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']>>> fruit = set(basket) # create a set without duplicates>>> fruitset(['orange', 'pear', 'apple', 'banana'])>>> 'orange' in fruit # fast membership testingTrue>>> 'crabgrass' in fruitFalse

>>> # Demonstrate set operations on unique letters from two words...>>> a = set('abracadabra')>>> b = set('alacazam')>>> a # unique letters in aset(['a', 'r', 'b', 'c', 'd'])>>> a - b # letters in a but not in bset(['r', 'd', 'b'])>>> a | b # letters in either a or bset(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'])>>> a & b # letters in both a and bset(['a', 'c'])>>> a ^ b # letters in a or b but not bothset(['r', 'd', 'b', 'm', 'z', 'l'])

>>> # Similarly to list comprehensions, set comprehensions are also supported:>>> a = {x for x in 'abracadabra' if x not in 'abc'}>>> aset(['r', 'd'])

Page 11: A tour of Python

DICTIONARIES>>> tel = {'jack': 4098, 'sape': 4139}>>> tel['guido'] = 4127>>> tel{'sape': 4139, 'guido': 4127, 'jack': 4098}>>> tel['jack']4098>>> del tel['sape']>>> tel['irv'] = 4127>>> tel{'guido': 4127, 'irv': 4127, 'jack': 4098}>>> tel.keys()['guido', 'irv', 'jack']>>> 'guido' in telTrue

>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]){'sape': 4139, 'jack': 4098, 'guido': 4127}

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

• Everything in Python is built with dictionaries: class properties, methods, imports...

• If order is important there is ordered dictionary: OrderedDict.

Dictionarycomprehension

Page 12: A tour of Python

LOOPING TECHNIQUES>>> for i, v in enumerate(['tic', 'tac', 'toe']):... print i, v...0 tic1 tac2 toe

>>> questions = ['name', 'quest', 'favorite color']>>> answers = ['lancelot', 'the holy grail', 'blue']>>> for q, a in zip(questions, answers):... print 'What is your {0}? It is {1}.'.format(q, a)...What is your name? It is lancelot.What is your quest? It is the holy grail.What is your favorite color? It is blue.

>>> for i in reversed(xrange(1,10,2)):... print i,...9 7 5 3 1

>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']>>> for f in sorted(set(basket)):... print f...applebananaorangepear

Page 13: A tour of Python

GENERATORSl = [1, 2, 3, 4, 5]d = (str(x) for x in l if x % 2 == 0)>>> <generator object <genexpr> at 0x106708410>

tuple(d)>>> ('2', '4')

d>>> <generator object <genexpr> at 0x106708410>

tuple(d)>>>()

# Sum up the bytes transferred in an Apache server log using# generator expressions

wwwlog = open("access-log")bytecolumn = (line.rsplit(None,1)[1] for line in wwwlog)bytes = (int(x) for x in bytecolumn if x != '-')print "Total", sum(bytes)

def countdown(n): print "Counting down from", n while n > 0: yield n n -= 1 print "Done counting down"

for i in countdown(10): print i

Page 14: A tour of Python

COROUTINESdef grep(pattern): print "Looking for %s" % pattern while True: line = (yield) if pattern in line: print line,

g = grep("python")g.next()g.send("Yeah, but no, but yeah, but no")g.send("A series of tubes")g.send("python generators rock!")

Page 15: A tour of Python

NAMESPACES AND SCOPES

Namespace

Maps names to objects

Implemented as dictionaries

Examples

Built in names

Global names in a module

Local names in a function invocation

No relation between names in different modules

Lifetime

Built in when Python starts (also called __builtin__ module)

Global for a module when definition is read in

Local when the function is called, deleted when function returns

Scope

Textual region of a Python program where a namespace is directly accessible

Determined statically, used dynamically

What?

During execution, there are at least three nested scopes:

Innermost scope, contains local names

Scopes of any enclosing functions

Current module's global names

Built in names

Assignments to names always go into the innermost scope

What?The global scope of a function defined in a module is that module’s namespace, no matter from where or by what alias the function is called

Class definitions place yet another namespace in the local scope.

#!/usr/bin/python

def multiply_b_f(value): def multiply_by(x): return x * value return multiply_by

# Lexical scoping.my_func = multiply_b_f(2)value = 3print my_func(10)

>>>20

Page 16: A tour of Python

CLASSESclass Mapping:

def __init__(self, iterable): self.items_list = [] self.__update(iterable)

def update(self, iterable): for item in iterable: self.items_list.append(item)

__update = update # Private copy of original update() method.

class MappingSubclass(Mapping):

def update(self, keys, values): # provides new signature for update() # but does not break __init__() for item in zip(keys, values): self.items_list.append(item)

class B: passclass C(B): passclass D(C): pass

for c in [B, C, D]: try: raise c() except D: print "D" except C: print "C" except B: print "B"

>>> class Complex:... def __init__(self, realpart, imagpart):... self.r = realpart... self.i = imagpart...>>> x = Complex(3.0, -4.5)>>> x.r, x.i(3.0, -4.5)

• Data attributes override method attributes with the same name.

• Passing an object is cheap since only a pointer is passed by the implementation; and if a function modifies an object passed as an argument, the caller will see the change.

class Foo(object): # Class variable. DUMMY = 1 def bar(self): return self.DUMMY + 1 def baz(self, new_value): self.DUMMY = new_value a = Foo()b = Foo()b.baz(2)

# Which one fails?assert Foo.DUMMY == a.DUMMYassert Foo.DUMMY == b.DUMMY

# A: self.__class__.DUMMY

Page 17: A tour of Python

GENERATOR VS. ITERATOR• Generators and iterators work the same.

• But not in multithreaded environment! Think about counters:

• You cannot call a generator that is already executing.

• You can lock protect iterator state and call it many times concurrently.

def squares(start, stop): """Generator.""" for i in xrange(start, stop): yield i * i class Squares(object): """Iterator.""" def __init__(self, start, stop): self.start = start self.stop = stop def __iter__(self): return self def next(self): # Lock here. if self.start >= self.stop: raise StopIteration current = self.start * self.start self.start += 1 return current

for i in squares(1, 5): print i,

# Inline generator:for i in (i*i for i in xrange(1, 5)): print i,

sq_range = Squares(1, 5)for i in sq_range: print i, >>> 1 4 9 16

Page 18: A tour of Python

FUNCTION ARGUMENTS• Never use keyword argument for a function that doesn't explicitly define

one. If you do that you’ve introduced a global variable!

• In your tests use the function call the same way you use it in production code: it can catch these bugs.

def foo(x, y): print x ** y

foo(2, 3)foo(2, y=3)foo(x=2, y=3)

def foo(base, exponent): print base ** exponent

foo(x=2, y=3)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: foo() got an unexpected keyword argument 'x'

Page 19: A tour of Python

CONTEXT MANAGERSimport sysfrom StringIO import StringIO

class redirect_stdout: def __init__(self, target): # Save stdout and target. self.stdout = sys.stdout self.target = target # Do this before. def __enter__(self): # Replace stdout with target. sys.stdout = self.target # Do this after. def __exit__(self, type, value, tb): # Restore stdout. sys.stdout = self.stdout

out = StringIO()with redirect_stdout(out): # Print goes to StringIO object now! print 'Test'

# Verify:>>> out.getvalue() == 'Test\n'True

f = open("hello.txt")try: for line in f: print line,finally: f.close()

with open("hello.txt") as f: for line in f: print line,

• __enter__() defines what the context manager should do at the beginning of the block created by the with statement. Note that the return value of __enter__ is bound to the target of the with statement, or the name after the as.

• __exit__(self, exception_type, exception_value, traceback) defines what the context manager should do after its block has been executed (or terminates).

• __enter__ and __exit__ can be useful for specific classes that have well-defined and common behavior for setup and cleanup.

Page 20: A tour of Python

DECORATORS• Decorator expressions are

evaluated when the function is defined, in the scope that contains the function definition.

• The result must be a callable, which is invoked with the function object as the only argument.

• The returned value is bound to the function name instead of the function object. Multiple decorators are applied in nested fashion.

import time

def timeit(func): """Decorator for measuring function run time.

Args: func: Function to be wrapped, passed implicitly through "@..." call.

Returns: Wrapped function.

""" def function_call_wrap(*args, **kwargs): try: start_time = time.time() return func(*args, **kwargs) finally: logger_func("%s() took %fms.", func.func_name, (time.time() - start_time) * 1000)

return function_call_wrap

def sleep1(): time.sleep(1) @timeitdef sleep2(): time.sleep(2)

Page 21: A tour of Python

RUN VS. IMPORT• Module imports trigger __init__.py execution. Imports are

actually running a code.

• Running a code from the same folder would not see it as a module and __init__.py wouldn’t run! Read an explanation athttp://stackoverflow.com/a/465129.

• Stay on the safe side: know what you are initializing.

• from foo import bar — considered harmful.

Page 22: A tour of Python

MODULES AND EXCEPTIONS• Modules or packages should define their own domain-specific base exception

class, which should be subclassed from the built-in Exception class.

• “Modules should have short, all-lowercase names.” (Though there are historical exceptions: StringIO.)

• Module level exceptions enable catching all errors that can be raised by one module only. Very useful for debugging and testing.

class Error(Exception): """Base class for exceptions in this module."""

class RedisLockError(Error): """Base class for lock exceptions."""

Page 23: A tour of Python

EXCEPTION CATCHING• When catching exceptions, mention

specific exceptions whenever possible instead of using a bare except: clause.

• If you want to catch all exceptions that signal program errors, use except Exception:(bare except is equivalent to except BaseException:).

try: do_something()except: # Diaper pattern. print "Error"

Page 24: A tour of Python

def convert_to_named_tuple(original_class): """Replace class declaration with named tuple.

This decorator is to be used when one uses class for storing constants.

Note: this will work only for classes with constants, not with any other declared methods.

Example usage::

@convert_to_named_tuple class important_constants(object): PI = 3.141 e = 2.718

print important_constants.PI # Prints 3.141 important_constants.PI = 2 # Raises exception!

Args: original_class: A class declaration.

Returns: Named tuple object in place of the decorated class.

""" @wraps(original_class) def replace_class_with_named_tuple(): constant_value_dict = dict() for attribute in original_class.__dict__: if not attribute.startswith("__"): constant_value_dict[attribute] = ( original_class.__dict__[attribute]) replacement_tuple = namedtuple( original_class.__class__.__name__, " ".join(constant_value_dict.iterkeys())) args = constant_value_dict.values() return replacement_tuple(*args)

return replace_class_with_named_tuple()

DOCUMENTATION

• PEP-257 talks about docstring conventions.

• “Comments that contradict the code are worse than no comments. Always make a priority of keeping the comments up-to-date when the code changes!”

• pydoc -p <port>: See all modules in production. Use it as a local Python library reference.

Page 25: A tour of Python

ARGPARSEparser = argparse.ArgumentParser( prog="smm", description="Management")parser.add_argument( "--version", action="version", version="%(prog)s 0.1")parser.add_argument( "--log", action="store", choices=("debug", "info", "warning", "error", "critical"), default="warning")

# Default arguments for each subparser: add/rm/list.

parent_parser = argparse.ArgumentParser(add_help=False)parent_parser.add_argument( "-l", "--labels", required=True, type=labels.valid_label_pair, nargs="+", metavar=("label1=value1", "label2=value2"), help="labels as 'key=value' pairs")parent_parser.add_argument( "-m", "--machines", required=True, type=machines.valid_machine_name, nargs="+", metavar=("machine_1", "machine_2"), help="machine names")parent_parser.add_argument( "--log", action="store", choices=("debug", "info", "warning", "error", "critical"), default="warning")

# Subparsers for add, rm, and list inherit the same

subparsers = parser.add_subparsers( title="subcommands", description="valid subcommands", dest="subparser_name", help="sub-commands")

parser_add = subparsers.add_parser( "add", parents=[parent_parser], help="add labels to machines")parser_add.add_argument( "add", help="add labels", action="store_true")parser_add.set_defaults(func=add_machines)

#...

def main(): args = parser.parse_args() logger.initialize_logger(args.log) logger.LOG.debug("Parsed command line and initialized logger.") logger.LOG.debug("Command line parsed: %s", args) logger.LOG.debug("Dispatching:") args.func(args) logger.LOG.debug("Done!")

Try not to use optparse module, it is deprecated.

Page 26: A tour of Python

GFLAGS• Google’s command line parsing library:

http://code.google.com/p/python-gflags/

• It has increased flexibility, including built-in support for Python types, and the ability to define flags in the source file in which they're used (major difference from OptParse).

FLAGS = gflags.FLAGS

gflags.DEFINE_integer( "port", 9001, "service port")gflags.RegisterValidator( "port", lambda port: 1024 < port <= 65535, message="must be in (1024, 65535] range") def main(argv) port = FLAGS.port

Page 27: A tour of Python

PEP8• Python Style Checker: python.org/dev/peps/pep-0008/

• Read it, and then read it again. It will teach you to write better and more reliable Python code. Add comments, be verbose, keep it clean.

• “Code should be written to minimize the time it would take for someone else to understand it.” — “The Art of Readable Code”, Dustin Boswell, Trevor Foucher.

• New code should (must) have test coverage. Use asserts. They will be completely ignored when the code is run in optimized mode (python -O).

Page 28: A tour of Python

PEP-8 ON IMPORTS• Always use the absolute package path for all imports. Even now that PEP-328

(“Imports: Multi-Line and Absolute/Relative”) is fully implemented in Python 2.5, its style of explicit relative imports is actively discouraged; absolute imports are more portable and usually more readable.

• Imports are always put at the top of the file, just after any module comments and docstrings, and before module globals and constants. Imports should be grouped in the following order: 1. Standard library imports 2. Related third party imports 3. Local application/library specific imports

• You should put a blank line between each group of imports.

Page 29: A tour of Python

“IS NONE” VS. “== NONE”• PEP 8 says: Comparisons to singletons like None

should always be done with is or is not, never the equality operators (==, !=).

• Beware of writing if x when you really mean if x is not None — e.g. when testing whether a variable or argument that defaults to None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context! A class is free to implement comparison any way it chooses, and it can choose to make comparison against None mean something

• Use x is not y instead of not x is y. Operator priority can be confusing and the second statement can be read as (not x) is y.

class Zero(): """A class that is zero.""" def __nonzero__(self): return False

class Len0(): """A class with zero length.""" def __len__(self): return 0

class Equal(): """A class that is equal to everything.""" def __eq__(self, other): return True

stuff = [None, False, 0, 0L, 0.0, 0j, (), [], {}, set(), '', float('NaN'), float('inf'), Zero(), Len0(), Equal()]for x in stuff: if x is None: print("{} is None ".format(x)) if x==None: print("{} == None ".format(x))

>>>None is None None == None <__main__.Equal instance at 0x84a80> == None

Page 30: A tour of Python

__DEL__ AND MEMORYclass SomeClass(object): pass

class SomeNastyClass(object): # Confuse garbage collection by adding __del__ method. If # circular reference is created it wouldn't know which one to # dispose of first and would let them stay in memory! def __del__(self): pass

def non_leaky_function(): """Non leaky function.""" foo = SomeClass() bar = SomeClass() foo.other = bar bar.other = foo del foo del bar return

def leaky_function(): """Leaky function.""" foo = SomeNastyClass() bar = SomeNastyClass() foo.other = bar bar.other = foo del foo del bar return

def log_memory_leaks(func, logger_func): """Decorator for detecting memory leaks.

Log what was not garbage collected after the function has returned.

Args: func: Function to be wrapped, passed implicitly through "@..." call. logger_func: Logging function to be called around the wrapped function.

Returns: Wrapped function.

""" @wraps(func) def function_call_wrap(*args, **kwargs): # Force garbage collection. gc.collect() # Different type instance counters before and after the function run. before = Counter([type(i) for i in gc.get_objects()]) try: return func(*args, **kwargs) finally: gc.collect() # Count instances by type after the run. Ignore object "before" # created in this decorator. after = Counter( [type(i) for i in gc.get_objects() if i is not before]) # Find instance types that have changed after the run. instance_diff = { i: after[i] - before[i] for i in after if after[i] != before[i]} if instance_diff: logger_func( "Memory usage after %s(args=%s, kwargs=%s): %s", func.func_name, args, kwargs, pprint.pformat(instance_diff))

return function_call_wrap

Use c

ontex

t man

ager

: “with ... :”

Page 31: A tour of Python

WHY TEST• No standard scoping: once a variable has come into existence it remains

until the enclosing function exits and not when the enclosing block terminates.

• No concept of data privacy, only obfuscation.

• No concept of declaration leads to ambiguity when you have multiple scopes. Instead of having one simple var keyword, Python has the global and nonlocal keywords (the latter is only available in Python 3).

• More errors are detected at run time than is desirable. Basically you have to make sure that all your code has been executed before you can say that the program is even semantically correct.

• Your friend: https://nose.readthedocs.org/en/latest/

Page 32: A tour of Python

PYCHARM COMMERCIAL

http://www.jetbrains.com/pycharm/

>>> # Python 2.X>>> True == FalseFalse>>> True = True>>> True = False>>> True == TrueTrue>>> True == FalseTrue

Page 33: A tour of Python

package main

import ( "fmt" "runtime")

func summer(ch chan<- uint64, from uint64, to uint64) { var sum uint64 = 0 for i := from; i <= to; i++ { sum += i } // Send the result. ch <- sum}

func main() { const upper uint64 = 1000000000 const workers uint64 = 8 var start_interval uint64 = 1 const step uint64 = upper / workers

// Make a channel that can buffer up to $workers numbers. ch := make(chan uint64, workers)

// Use up to 8 CPUs. This should nicely use quad core CPU with // hyperthreading. runtime.GOMAXPROCS(8)

// Dispatch workers, each with a different number segment. for i := uint64(0); i < workers; i++ { go summer(ch, start_interval, start_interval+step-1) start_interval += step }

// Read out results as they keep arriving to the channel (we block on the // channel until a value is ready). var sum uint64 = 0 for i := uint64(0); i < workers; i++ { sum += <-ch }

fmt.Println(sum)}

>real 0m0.302suser 0m2.165ssys 0m0.004s

#!/usr/bin/pythonprint sum(xrange(1, 1000000001))

>real 0m12.114suser 0m12.087ssys 0m0.012s

#!/usr/bin/perluse integer; $sum = 0; $sum += $_ for (1 .. 1000000000); print $sum;

>real 1m21.774suser 1m21.656ssys 0m0.061s

#include "stdio.h"

int main(int argc, char const *argv[]) { long sum = 0; for (long i = 1; i <= 1000000000L; sum+=i++) ; printf("%ld\n", sum); return 0;}

>real 0m2.465suser 0m2.461ssys 0m0.002s

109X

i=1

i = 500000000500000000

EXAMPLE: SUM

Page 34: A tour of Python

PARALLELIZE SUM!

#!/usr/bin/python

import multiprocessing

UPPER = 1000000000WORKERS = 8STEP = UPPER / WORKERS

pool = multiprocessing.Pool(processes=WORKERS)ranges = (xrange(lo, hi + 1) for (lo, hi) in zip(xrange(1, UPPER, STEP), xrange(STEP, UPPER + 1, STEP)))print sum(pool.map(sum, ranges))

>real 0m2.008suser 0m13.991ssys 0m0.051s

From 12 to 2 seconds.

Page 35: A tour of Python

FIBONACCI NUMBERS

f(n) =

8><

>:

0 n = 0

1 n = 1

f(n� 1) + f(n� 2) otherwise

#!/usr/bin/python

from timeit import timeit

def fib(n): assert n >= 0 if n == 0: return 0 if n == 1: return 1 return fib(n-1) + fib(n-2)

print(timeit( stmt="fib(30)", setup="from __main__ import fib", number=1))

$ python3.3 fib.py 0.8095278141554445

#!/usr/bin/python

import time

def timeit(func): def function_call_wrap(*args, **kwargs): try: start_time = time.time() return func(*args, **kwargs) finally: print(time.time() - start_time) return function_call_wrap

def fib(n): assert n >= 0 if n == 0: return 0 if n == 1: return 1 return fib(n-1) + fib(n-2)

@timeitdef fib30(): fib(30)

fib30()

python3.3 fib.py 0.794215202331543

#!/usr/bin/python

from timeit import timeitfrom functools import lru_cache

@lru_cache(maxsize=512)def fib(n): assert n >= 0 if n == 0: return 0 if n == 1: return 1 return fib(n-1) + fib(n-2)

print(timeit( stmt="fib(30)", setup="from __main__ import fib", number=1))

$python3.3 fib.py 0.0003443881869316101

f(30) = 832040

Page 37: A tour of Python

CRITICISM• Python is highly typed. Do you get function overloading based upon parameter type? No.

Can you stipulate the type of a parameter in a function declaration? No, this has to be coded within the function.

• Mutable default arguments (def foo(a=”abc”, b=[])).

• Documentation is generally good, but quite often it doesn’t go into enough detail.

• It is deceptively easy to start with, but to write serious code you have to know hidden stuff.

• All function arguments are essentially global variables! If you rename them you can break some code! Partially fixed in Python 3+.

• White space complicates refactoring.

• Anonymous or lambda functions are limited in their ability. However one can declare a named function in an inner scope and use that instead.

Page 38: A tour of Python

GIL• GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once.

This lock is necessary mainly because CPython's memory management is not thread-safe. However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.

• It prevents multithreaded CPython programs from taking full advantage of multiprocessor systems.

Page 39: A tour of Python

2.X OR 3.X$ pythonPython 2.7.2 (default, Oct 11 2012, 20:14:37) [GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwinType "help", "copyright", "credits" or "license" for more information.>>> 3/21>>> ^D

$ python3.3Python 3.3.1 (v3.3.1:d9893d13c628, Apr 6 2013, 11:07:11) [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwinType "help", "copyright", "credits" or "license" for more information.>>> 3/21.5>>> ^D

• Some libraries are still not ported to 3.X

• 2.7.X is the last 2.X version

• New features are added to 3.X, it is a better language.

• http://wiki.python.org/moin/Python2orPython3

Page 40: A tour of Python

GOOD TO KNOW• #!env python — it can mask the process name. You wouldn’t see

the name of the code running when listing processes on a machine.

• Unicode vs. normal strings: size difference exists for ASCII characters as well. u“Aleksa” takes twice the size of “Aleksa” (or even four times!). Differences in 2.X and 3.X.

• In all python projects you do not cd into a lower directory to run things. You stay at the top and run everything from there so that all of the system can access all the modules and files.

• http://www.aleksa.org/2013/03/python-resources.html