SlideShare une entreprise Scribd logo
1  sur  145
Télécharger pour lire hors ligne
A Few of My Favorite Things




         Mike Pirnat • AG Interactive • CodeMash 2012
A Few of My Favorite Things




         Mike Pirnat • AG Interactive • CodeMash 2012
A Few of My Favorite (Python) Things
Disclaimers
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) Things
The Language
_                                             (                   =
                                          255,
                                       lambda
                                V       ,B,c
                             :c    and Y(V*V+B,B, c
                                -1)if(abs(V)<6)else
               (              2+c-4*abs(V)**-0.4)/i
                 ) ;v,       x=1500,1000;C=range(v*x
                  );import struct;P=struct.pack;M,
            j ='<QIIHHHH',open('M.bmp','wb').write
for X in j('BM'+P(M,v*x*3+26,26,12,v,x,1,24))or C:
            i ,Y=_;j(P('BBB',*(lambda T:(T*80+T**9
                  *i-950*T **99,T*70-880*T**18+701*
                 T **9      ,T*i**(1-T**45*2)))(sum(
               [              Y(0,(A%3/3.+X%v+(X/v+
                                A/3/3.-x/2)/1j)*2.5
                             /x    -2.7,i)**2 for 
                                A       in C
                                       [:9]])
                                          /9)
                                        )     )

        http://preshing.com/20110926/high-resolution-mandelbrot-in-obfuscated-python
http://preshing.com/20110926/high-resolution-mandelbrot-in-obfuscated-python
The Interactive Shell

$ python
Python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build
2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for
more information.
>>>
Docstrings...
class Frobulator(object):
    """It frobulates things."""

    def __init__(self, doohickey):
        """A Frobulator needs a doohickey."""
        self.doohickey = doohickey

    def frobulate(self):
        """Frobulate ALL the things!"""
        print "Frobulating..."
        doodad = self.doohickey()
        return FrobulatedThing(doodad)


class FrobulatedThing(object):
    """A thing which has been frobulated."""

    def __init__(self, thing):
        """Make a thing into a frobulated thing."""
        self.thing = thing
...and Help
>>> help(Frobulator)

Help on class Frobulator in module frobulator:

class Frobulator(__builtin__.object)
 | It frobulates things.
 |
 | Methods defined here:
 |
 | __init__(self, doohickey)
 |      A Frobulator needs a doohickey.
 |
 | frobulate(self)
 |      Frobulate ALL the things!
 |
 ...
Comprehensions

• List comprehensions
• Set comprehensions
• Dictionary comprehensions
• Generator expressions
List Comprehensions

x = [item for item in series]

x = [do_something(item) for item in series if expression]

things = [Thingy.from_data(x) for x in database_results]

partiers = [x for x in codemashers if x.slides_done()]
List Comprehensions
booze = ['beer', 'wine', 'scotch', 'gin']
soft_drinks = ['water', 'soda', 'juice']

a = [(x, y) for x in booze for y in soft_drinks]

[('beer', 'water'), ('beer', 'soda'), ('beer', 'juice'),
('wine', 'water'), ('wine', 'soda'), ('wine', 'juice'),
('scotch', 'water'), ('scotch', 'soda'), ('scotch',
'juice'), ('gin', 'water'), ('gin', 'soda'), ('gin',
'juice')]
List Comprehensions


b = [x for x in zip(booze, soft_drinks)]

[('beer', 'water'), ('wine', 'soda'), ('scotch', 'juice')]
Set Comprehensions


s = {v for v in 'CODEMASH ROCKS' if v not in 'ABCD'}

set([' ', 'E', 'H', 'K', 'M', 'O', 'S', 'R'])
Dictionary Comprehensions
 d = {key: value for key, value in list_of_tuples}

 d = {
     'Mike': 'Python',
     'Jim': 'Ruby',
     'Brad': 'UX',
     ...
     }

 d1 = {val: key for key, val in d.items()}

 {'Python': 'Mike', 'Ruby': 'Jim', 'UX': 'Brad', ...}
Generators
def f(how_many):
    for number in range(how_many):
        if number**2 > 3:
            yield number * 2

for number in f(5):
    print number

4
6
8
Generator Expressions

gen = (2*x for x in range(5) if x**2 > 3)

for number in gen:
    print number

4
6
8
Properties

class Foo(object):

    def __init__(self, bar=42):
        self.set_bar(bar)

    def get_bar(self):
        return self.bar

    def set_bar(self, bar):
        self.bar = int(bar)
Properties
class Foo(object):

    def __init__(self, bar=42):
        self.bar = bar

    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, x):
        self._bar = int(x)
Properties
class Foo(object):

    def __init__(self, bar=42):
        self.bar = bar

    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, x):
        self._bar = int(x)
Properties

>>> foo = Foo()
>>> foo.bar
42
>>> foo.bar = 'abc'
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "<stdin>", line 9, in bar
ValueError: invalid literal for int() with base 10:
'abc'
Decorators

• That funny-looking @ thing
• Similar to Java’s annotations
• Replaces a function with a wrapper
• Augment functionality in a reusable way
Decorators
def be_excellent(wrapped):
    def wrapper(*args, **kwargs):
        print "Be excellent to each other..."
        return wrapped(*args, **kwargs)
    return wrapper

@be_excellent
def party_on(who):
    print "...and party on, {0}!".format(who)

>>> party_on('dudes')
Be excellent to each other...
...and party on, dudes!
Context Managers
• That funny “with” thing
• Simplify calling code that needs setup and
  teardown
• Alternative to try/finally structures
• Acquire locks, open and close files, do
  database transactions, etc.
Before Context Managers

frobulator = Frobulator(...)

try:
    frobulator.frobulate()
finally:
    frobulator.cleanup()
After Context Managers


with Frobulator(...) as frobulator:
    frobulator.frobulate()
class Frobulator(object):

    def __init__(self, ...):
        ...

    def __enter__(self):
        print "Preparing to frobulate..."
        return self

    def __exit__(self, exc_type, exc_value, exc_tb):
        print "Frobulation complete!"

    def frobulate(self):
        print "Frobulating!"
        ...
with Frobulator() as frobulator:
    frobulator.frobulate()


Preparing to frobulate...
Frobulating!
Frobulation complete!
import contextlib

@contextlib.contextmanager
def make_frobulator():
    print "Preparing to frobulate..."
    yield Frobulator()
    print "Frobulation complete!"


with make_frobulator() as frobulator:
    frobulator.frobulate()


Preparing to frobulate...
Frobulating!
Frobulation complete!
The Standard Library
Itertools

• Tools for iterating on sequences
• Inspired by functional languages
• Fast and memory efficient
• Combine to express more complicated
  algorithms
Itertools: chain

from itertools import chain

for x in chain([1, 2, 3], [42, 1138, 2112]):
     print x,


1 2 3 42 1138 2112
Itertools: izip

from itertools import izip

for x in izip([1, 2, 3], [42, 1138, 2112]):
    print x,


(1, 42) (2, 1138) (3, 2112)
Itertools: islice
from itertools import islice, count

for x in islice(count(), 5):
    print x,

for x in islice(count(), 5, 10):
    print x,

for x in islice(count(), 0, 100, 10):
    print x,

0 1 2 3 4
5 6 7 8 9
0 10 20 30 40 50 60 70 80 90
Itertools: islice
from itertools import islice, count

for x in islice(count(), 5):
    print x,

for x in islice(count(), 5, 10):
    print x,

for x in islice(count(), 0, 100, 10):
    print x,

0 1 2 3 4
5 6 7 8 9
0 10 20 30 40 50 60 70 80 90
Itertools: imap


from itertools import imap

for thingy in imap(Thingy.from_data, database_results):
    ...
Itertools: cycle
from itertools import cycle

for x in cycle(['wake up', 'meet Ned', 'romance Rita']):
    print x

wake up
meet Ned
romance Rita
wake up
meet Ned
romance Rita
wake up
meet Ned
...
Itertools: repeat

from itertools import repeat

for x in repeat("stop hitting yourself", 5):
    print x

stop   hitting   yourself
stop   hitting   yourself
stop   hitting   yourself
stop   hitting   yourself
stop   hitting   yourself
Functools

• Tools for manipulating functions
• Partial
• Wraps a callable with default arguments
• Alternative to lambdas and closures
Functools: Partial
from functools import partial

def f(a, b=2):
    print a, b

f1 = partial(f, 'fixed_a')
f2 = partial(f, b='fixed_b')

>>> f1(b=1138)
fixed_a 1138

>>> f2(1138)
1138 fixed_b
Functools: Partial
def category_is(category, item):
    categories = [x.lower() for x in item.categories]
    if category.lower() in categories:
        return True
    return False

is_python = partial(category_is, 'python')
is_cat_pictures = partial(category_is, 'catpix')

...

python_posts = [item for item in blog_posts if is_python(item)]

cat_posts = [item for item in blog_posts if is_cat_pictures(item)]
Collections
• Beyond the basic list, dict, tuple, and set...
• Counter
• Defaultdict
• OrderedDict
• Namedtuple
• ...and more
Counter
counter = {}
for char in "Hello there, CodeMash!":
    if char not in counter:
        counter[char] = 1
    else:
        counter[char] += 1

print counter

{'a': 1, ' ': 2, 'C': 1, 'e': 4, 'd': 1, 'H': 1, 'M': 1,
'l': 2, 'o': 2, ',': 1, 's': 1, 'r': 1, '!': 1, 't': 1,
'h': 2}
Counter
counter = {}
for char in "Hello there, CodeMash!":
    if char not in counter:
        counter[char] = 1
    else:
        counter[char] += 1

print counter

{'a': 1, ' ': 2, 'C': 1, 'e': 4, 'd': 1, 'H': 1, 'M': 1,
'l': 2, 'o': 2, ',': 1, 's': 1, 'r': 1, '!': 1, 't': 1,
'h': 2}
Counter

from collections import Counter
counter = Counter("Hello there, CodeMash!")
print counter

Counter({'e': 4, ' ': 2, 'l': 2, 'o': 2, 'h': 2, 'a': 1,
'C': 1, 'd': 1, 'H': 1, 'M': 1, ',': 1, 's': 1, 'r': 1,
'!': 1, 't': 1})
Counter

from collections import Counter
counter = Counter("Hello there, CodeMash!")
print counter

Counter({'e': 4, ' ': 2, 'l': 2, 'o': 2, 'h': 2, 'a': 1,
'C': 1, 'd': 1, 'H': 1, 'M': 1, ',': 1, 's': 1, 'r': 1,
'!': 1, 't': 1})
Namedtuple
import math

def distance(a, b):
    return math.sqrt(
        (a[0] - b[0])**2 +
        (a[1] - b[1])**2 +
        (a[2] - b[2])**2
    )

a = (1, 2, 3)
b = (-1, -2, 42)
print distance(a, b)

39.25557285278104
Namedtuple
from collections import namedtuple
Point = namedtuple('Point', 'x y z')

def distance(a, b):
    return math.sqrt(
        (a.x - b.x)**2 +
        (a.y - b.y)**2 +
        (a.z - b.z)**2
    )

a = Point(x=1, y=2, z=3)
b = Point(-1, -2, 42)
print distance(a, b)

39.25557285278104
Difflib
s1 = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Phasellus dui nunc, faucibus id ullamcorper eget, tempus
vitae nisl. Donec quis semper risus. Curabitur sit amet
tellus eget metus accumsan porta nec nec lorem. Ut vitae
sem nisl. Praesent pulvinar feugiat nibh fringilla
semper. Nullam cursus tempor lorem ut egestas. Nullam
suscipit gravida turpis ac porttitor. Curabitur eleifend
augue at risus commodo pretium. Aliquam eget magna
risus, ut lobortis metus. Cum sociis natoque penatibus
et magnis dis parturient montes, nascetur ridiculus mus.
Etiam non magna sit amet nulla porttitor molestie sit
amet vel sem. Vestibulum sit amet nisl a velit
adipiscing porta id non urna. Duis ullamcorper dictum
ipsum sit amet congue.
"""
Difflib
s2 = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Phasellus dui nunc, faucibus id ullamcorper eget, tempus
vitae nisl. Donec quis semper risus. Curabitur sit amet
tellus eget metus accumsan porta nec nec lorem. Ut vitae
sem nisl. Praesent pulvinar feugiat nibh fringilla
semper. Nullam cursus tempor lorem ut egestas. Nullam
suscipit gravida turpis ac porttitor. Curabitur eleifend
augue at risus commodo pretium. Aliquam eget magna
risus, ut lobortis montes. Cum sociis natoque penatibus
et magnis dis parturient metus, nascetur ridiculus mus.
Etiam non magna sit amet nulla porttitor molestie sit
amet vel sem. Vestibulum sit amet nisl a velit
adipiscing porta id non urna. Duis ullamcorper dictum
ipsum sit amet congue.
"""
Difflib

import difflib

differ = difflib.Differ()
diff = differ.compare(s1.splitlines(), s2.splitlines())
print 'n'.join(diff)
Difflib
  Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  Phasellus dui nunc, faucibus id ullamcorper eget, tempus
  vitae nisl. Donec quis semper risus. Curabitur sit amet
  tellus eget metus accumsan porta nec nec lorem. Ut vitae
  sem nisl. Praesent pulvinar feugiat nibh fringilla
  semper. Nullam cursus tempor lorem ut egestas. Nullam
  suscipit gravida turpis ac porttitor. Curabitur eleifend
  augue at risus commodo pretium. Aliquam eget magna
- risus, ut lobortis metus. Cum sociis natoque penatibus
?                      --

+ risus, ut lobortis montes. Cum sociis natoque penatibus
?                     +++

- et magnis dis parturient montes, nascetur ridiculus mus.
?                           ^^ ^

+ et magnis dis parturient metus, nascetur ridiculus mus.
?                           ^ ^

  Etiam non magna sit amet nulla porttitor molestie sit
  amet vel sem. Vestibulum sit amet nisl a velit
  adipiscing porta id non urna. Duis ullamcorper dictum
  ipsum sit amet congue.
Difflib


diff = difflib.unified_diff(
        s1.splitlines(), s2.splitlines(), lineterm='')
print 'n'.join(diff)
Difflib

---
+++
@@ -7,8 +7,8 @@
 semper. Nullam cursus tempor lorem ut egestas. Nullam
 suscipit gravida turpis ac porttitor. Curabitur eleifend
 augue at risus commodo pretium. Aliquam eget magna
-risus, ut lobortis metus. Cum sociis natoque penatibus
-et magnis dis parturient montes, nascetur ridiculus mus.
+risus, ut lobortis montes. Cum sociis natoque penatibus
+et magnis dis parturient metus, nascetur ridiculus mus.
 Etiam non magna sit amet nulla porttitor molestie sit
 amet vel sem. Vestibulum sit amet nisl a velit
 adipiscing porta id non urna. Duis ullamcorper dictum
Ast

• Use Python to process abstract syntax trees
  of Python grammar
• Helps introspect about what the current
  grammar looks like
• Helps write secure code
Ast

# Danger:
foo = eval(bar)

# Safe:
foo = ast.literal_eval(bar)
Multiprocessing
• Like threading, but with subprocesses
• Local and remote concurrency
• Spawn processes or entire pools
• Communicate via queues or pipes
• Shared state via shared memory or
  manager/server process
import os
from multiprocessing import Process

def info(title):
    print title
    print 'parent process:', os.getppid()
    print 'process id:', os.getpid()

def f(name):
    info('function f')
    print 'hello', name

if __name__ == '__main__':
    info('main')
    p = Process(target=f, args=('world',))
    p.start()
    p.join()
$ python process.py
main
parent process: 18647
process id: 31317
----------
function f
parent process: 31317
process id: 31318
----------
hello world
import os
from multiprocessing import Pool

def g(x):
    info('function g('+str(x)+')')
    return x * x

if __name__ == '__main__':
    info('main')
    pool = Pool(2)
    print pool.map(g, range(100))
$ python process.py     parent process: 31369
main                    parent process: 31369
module name: __main__   process id: 31370
parent process: 18647   process id: 31371
process id: 31369       ----------
----------              ----------
function g(0)           function g(4)
module name: __main__   module name: __main__
parent process: 31369   parent process: 31369
process id: 31370       function g(14)
----------              process id: 31370
function g(1)           module name: __main__
module name: __main__   ----------
parent process: 31369   parent process: 31369
process id: 31370       function g(5)
----------              process id: 31371
function g(13)          module name: __main__
function g(2)
module name: __main__   ...
parent process: 31369
process id: 31370       [0, 1, 4, 9, 16, 25, ..., 8836,
----------              9025, 9216, 9409, 9604, 9801]
module name: __main__
function g(3)
module name: __main__
Third Party Packages
Third Party Packages

• Most available on PyPI--http://pypi.python.org
• pip install packagename
• easy_install packagename
Virtualenv

• Makes an isolated Python environment
• Don’t pollute your global site-packages
• Insulates Python projects from one another
• Don't have to be root
Virtualenv
$ virtualenv directory

$ virtualenv --python=/path/to/specific/python directory

$ cd directory
$ . bin/activate

$ easy_install whatever
$ pip install whatever

...do stuff...

$ deactivate
Datetime and Dateutil
• Python’s datetime provides date, time,
  datetime, and timedelta objects
• Dateutil provides powerful extensions
• Parsing
• Olson-driven timezones
• Recurrence
Parsing

>>> from dateutil.parser import parse

>>> parse('01/01/2012')
datetime.datetime(2012, 1, 1, 0, 0)

>>> parse('2012-01-01')
datetime.datetime(2012, 1, 1, 0, 0)
Timezones
>>> from dateutil import zoneinfo

>>> zone = zoneinfo.gettz('US/Eastern')
>>> zone
tzfile('America/New_York')
>>> zone2 = zoneinfo.gettz('US/Hawaii')

>>> dt = datetime.now(zone)
>>> dt
datetime.datetime(2012, 1, 13, 13, 46, 54, 997825,
tzinfo=tzfile('America/New_York'))

>>> dt.astimezone(zone2)
datetime.datetime(2012, 1, 13, 8, 46, 54, 997825,
tzinfo=tzfile('Pacific/Honolulu'))
Recurrence
>>> from dateutil.rrule import rrule, YEARLY, MONTHLY,
WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY, BY_EASTER

>>> rr = rrule(YEARLY, dtstart=datetime(1948, 2, 24))

>>> rr.after(datetime(2012, 1, 1))
datetime(2012, 2, 24, 0, 0)

>>> rr.between(datetime(2010, 1, 1),
        datetime(2012, 1, 1))
[datetime(2010, 2, 24, 0, 0),
        datetime(2011, 2, 24, 0, 0)]
howoldismykid.com
def periods_between(freq, start_date, end_date):

    # dateutil.rrule falls down for monthly recurrences where the start
    # date's day is greater than the number of days in a subsequent month
    # in the range; ie, when start date is 10/31/2010, and end date is
    # 3/13/2011, rrule's between will only produce 2 instances, 12/31 and
    # 1/31, rather than 4.
    if freq == MONTHLY and start_date.day > 28:
        start_date = datetime.datetime(start_date.year, start_date.month,
                28, start_date.hour, start_date.minute, start_date.second)

    # Same problem but for "Pirates of Penzance" leap day birthdays...
    elif freq == YEARLY and is_leap_day(start_date):
        start_date = datetime.datetime(start_date.year, start_date.month,
                28, start_date.hour, start_date.minute, start_date.second)

    rr = rrule(freq, dtstart=start_date)
    periods = len(rr.between(start_date, end_date))
    return periods
howoldismykid.com
>>> start_date = datetime(2007, 9, 10)
>>> end_date = datetime(2012, 1, 13)

>>> periods_between(YEARLY, start_date, end_date)
4

>>> periods_between(MONTHLY, start_date, end_date)
52

>>> periods_between(WEEKLY, start_date, end_date)
226

>>> periods_between(DAILY, start_date, end_date)
1585
Nose

• Find, run, and report results of test suites
• Low-friction setup
• Extendable with plugins (more later)
• http://readthedocs.org/docs/nose/en/latest/
Nose

# test_foo.py

def test_a_thing():
    assert False

def test_another_thing():
    assert True
Nose
$ nosetests tests/test_foo.py
F.
======================================================================
FAIL: test_foo.test_a_thing
----------------------------------------------------------------------
Traceback (most recent call last):
   File "/Users/mpirnat/Code/frobulator/lib/python2.7/site-packages/
nose-1.1.2-py2.7.egg/nose/case.py", line 197, in runTest
     self.test(*self.arg)
   File "/Users/mpirnat/Code/frobulator/src/frobulator/tests/test_foo.py",
line 2, in test_a_thing
     assert False
AssertionError

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)
Nose
class TestWhenFrobulating(object):

    def setup(self):
        self.frobulator = Frobulator()
        self.frobulator.frobulate()

    def test_that_it_frobulated(self):
        assert self.frobulator.has_frobulated

    def teardown(self):
        self.frobulator.cleanup()
Nose

$ nosetests
.
--------------------------------------------------------
Ran 1 test in 0.005s

OK
Nose: Useful Flags

• --processes=number
• -x
• --pdb
• --pdb-failures
• --failed
Nose Plugins
• Add custom behavior to your test run
• Get coverage statistics (coverage)
• Measure cleanliness with PEP-8 (tissue)
• Emit human-readable spec-style results
  (pinocchio)
• Or write your own...
class TestGeneratesLotsOfFailures(object):

    def test_generates_failures(self):

        def _make_a_test(i):
            # start with some wins
            if i < 7:
                assert True

            # but then it hits the fan...
            elif i < 30:
                assert False

            # then be a little random
            elif i % 3 == 0:
                assert False
            else:
                assert True

        for i in range(50):
            yield _make_a_test, i
$ nosetests test_epic_fail.py

.......FFFFFFFFFFFFFFFFFFFFFFFF..F..F..F..F..F..F.
[lots of test failure output; use your imagination...]
--------------------------------------------------------
Ran 50 tests in 0.010s

FAILED (errors=30)
A Few of My Favorite (Python) Things
import os
from nose.plugins import Plugin

class F7U12(Plugin):

    name = 'f7u12'
    enabled = True

    def options(self, parser, env=os.environ):
        super(F7U12, self).options(parser, env=env)

    def configure(self, options, config):
        super(F7U12, self).configure(options, config)
        self.config = config
        if not self.enabled:
            return
def setOutputStream(self, stream):
    self.stream = stream
    return self.stream

def begin(self):
    self.failure_count = 0

def handleFailure(self, test, err):
    self.failure_count += 1

    if self.failure_count < 8:
        self.stream.write('F')
    else:
        self.stream.write('U')
    return True
$ nosetests --with-f7u12 test_epic_fail.py

.......FFFFFFFFUUUUUUUUUUUUUUUU..U..U..U..U..U..U.
[lots of test failure output; use your imagination...]
--------------------------------------------------------
Ran 50 tests in 0.010s

FAILED (errors=30)
Mock
• Mock object framework
• Avoid writing custom stubs
• Uses “Action/Assert” model (not “Record/
  Replay”)
• Can also patch out module and class
  attributes in the scope of a test
• http://www.voidspace.org.uk/python/mock/
Mock

from mock import Mock

foo = Mock()
foo.bar()
foo.bar.baz(42)
foo.bar.baz.return_value = "whatever"

assert foo.bar.called
foo.bar.baz.assert_called_with(42)
Mock

class TestWhenFrobulating(object):

    def setup(self):
        self.doohickey = Mock()
        self.frobulator = Frobulator(self.doohickey)
        self.frobulator.frobulate()

    def test_it_uses_the_doohickey(self):
        assert self.doohickey.called
Mock
from mock import patch

class TestWhenFrobulating(object):

    @patch('frobulator.DingleHopper')
    def setup(self, dingle_hopper_class):
        self.dingle_hopper = Mock()
        dingle_hopper_class.return_value = 
                self.dingle_hopper
        self.frobulator = Frobulator()
        self.frobulator.frobulate()

    def test_it_uses_a_dingle_hopper(self):
        assert self.dingle_hopper.called
Coverage

• Measure coverage of your codebase during
  program execution
• Integrates with several test runners to
  measure test coverage
• http://nedbatchelder.com/code/coverage/
#!/usr/bin/env python

class Frobulator(object):
    """It frobulates things."""

    def __init__(self, doohickey):
        """A Frobulator needs a doohickey."""
        self.doohickey = doohickey

    def frobulate(self):
        """Frobulate ALL the things!"""
        print "Frobulating..."
        doodad = self.doohickey()
        return FrobulatedThing(doodad)


class FrobulatedThing(object):
    """A thing which has been frobulated."""

    def __init__(self, thing):
        """Make a thing into a frobulated thing."""
        self.thing = thing


if __name__ == '__main__':
    x = FrobulatedThing(42)
#!/usr/bin/env python

class Frobulator(object):
    """It frobulates things."""

    def __init__(self, doohickey):
        """A Frobulator needs a doohickey."""
        self.doohickey = doohickey

    def frobulate(self):
        """Frobulate ALL the things!"""
        print "Frobulating..."
        doodad = self.doohickey()
        return FrobulatedThing(doodad)


class FrobulatedThing(object):
    """A thing which has been frobulated."""

    def __init__(self, thing):
        """Make a thing into a frobulated thing."""
        self.thing = thing


if __name__ == '__main__':
    x = FrobulatedThing(42)
$ coverage run frobulator.py

$ coverage report -m
Name         Stmts   Miss Cover    Missing
------------------------------------------
frobulator      12      4    67%   8, 12-14
from mock import Mock, patch
from frobulator import Frobulator, FrobulatedThing


class TestWhenFrobulating(object):

    def setup(self):
        self.doohickey = Mock()
        self.doohickey.return_value = 42

        self.frobulator = Frobulator(self.doohickey)
        self.result = self.frobulator.frobulate()

    def test_it_uses_a_doohickey(self):
        assert self.doohickey.called

    def test_it_returns_a_frobulated_thing(self):
        assert isinstance(self.result, FrobulatedThing)
$ nosetests --with-coverage --cover-package frobulator
..
Name         Stmts    Miss Cover   Missing
------------------------------------------
frobulator      12       1   92%   26
------------------------------------------
Ran 2 tests in 0.008s

OK
Useful Flags

• --cover-erase
• --cover-inclusive
• --cover-tests
Lettuce

• Like Cucumber
• BDD test framework
• Natural language augmented by code
• Big wins pairing Devs + QA + Biz
• http://lettuce.it/
Lettuce Vocabulary

• Features
• Scenarios
• Steps
• World
• Terrain
Feature: The website has a homepage
    In order to demo Lettuce
    As a presenter
    I want to test the homepage of a website

    Scenario: Verify the site is up
        Given I access the url "http://localhost:8000/"
        Then I get a status "200"
from lettuce import step, world
from nose.tools import assert_equals
import requests


@step(r'I access the url "(.*)"')
def access_url(step, url):
    world.response = requests.get(url)


@step(r'I get a status "(.*)"')
def get_status(step, expected_status):
    expected_status = int(expected_status)
    assert_equals(world.response.status_code,
            expected_status)
Snake-Guice

• Framework for Dependency Injection
• Reduce coupling!
• Improve testability!
• http://code.google.com/p/snake-guice/
Snake-Guice
• Bind identifiers to things you want to inject
• Decorate code with injection hints
• Use injector to get instance with all
  dependencies resolved and injected
• Construct with mocks in tests, minimize the
  need for patching
Define the Identifier


class IFrobulator(object):
    pass
Decorate Your Code

from snakeguice import inject


class WankelRotator(object):

    @inject(frobulator=IFrobulator)
    def __init__(self, frobulator):
        self.frobulator = frobulator
Decorate Your Code

from snakeguice import inject


class WankelRotator(object):

    @inject(frobulator=IFrobulator)
    def __init__(self, frobulator):
        self.frobulator = frobulator
Configure Bindings

from frobulator import Frobulator


class BindingModule(object):

    def configure(self, binder):
        binder.bind(IFrobulator, to=Frobulator)
Get an Instance

from snakeguice import Injector
import WankelRotator

injector = Injector(BindingModule())
rotator = injector.get_instance(WankelRotator)
Requests

• A human-friendly alternative to urllib2
• Maturing rapidly
• http://python-requests.org/
Using Requests

import requests

# Authentication!
r = requests.get('https://api.github.com',
        auth=('user', 'pass'))

print r.status_code
print r.headers['content-type']
Using Requests

# Posting name-value pair form data
post_data = {'foo': 'bar', 'baz': 'quux', ...}
r = requests.post(url, data=post_data)

# Posting a glob of JSON
r = requests.post(url, data=json.dumps(post_data))

# Multipart file attachment
files = {'my_file.xls': open('my_file.xls', 'rb')}
r = requests.post(url, files=files)
Using Requests

# Custom headers!
headers = {'X-foo': 'bar'}
r = requests.get(url, headers=headers)

# Cookies!
cookies = {'a_cookie': 'is delicious'}
r = requests.get(url, cookies=cookies)
Pylons
• http://docs.pylonsproject.org/en/latest/docs/
  pylons.html
• MVCish web framework
• Glues together several component projects
• Can use your preferred components
• Somewhat dead (evolved into Pyramid)
Pylons
• Request/response: webob
• URL dispatch: routes
• Input validation: formencode
• Persistence/ORM: sqlalchemy
• Session: beaker
• Templates: mako
from routes import Mapper


def make_map(config):
    """Create, configure and return the routes Mapper"""
    map = Mapper(directory=config['pylons.paths']['controllers'],
                 always_scan=config['debug'])
    ...

    map.connect('/', controller='main', action='index')
    map.connect('/contact', controller='contact', action='index',
            conditions={'method':'GET'})
    map.connect('/contact', controller='contact', action='send',
            conditions={'method':'POST'})

    return map
from howoldismykid.lib.base import BaseController, 
        render


class MainController(BaseController):

    def index(self):
        # Return a rendered template
        return render('/main.mako')
from formencode import Schema, validators

class ContactForm(Schema):
    email = validators.Email(not_empty=True)
    subject = validators.String(not_empty=True)
    message = validators.String(not_empty=True)
from pylons.decorators import validate
from howoldismykid.lib.base import BaseController, render
from howoldismykid.model.forms import ContactForm

class ContactController(BaseController):

    def __init__(self, *args, **kwargs):
        BaseController.__init__(self, *args, **kwargs)
        self.emailer = Emailer(SMTP, USER, PW, FAKE_EMAIL)

    def index(self):
        # Return a rendered template
        return render('/contact.mako')

    @validate(schema=ContactForm(), form="index", prefix_error=False)
    def send(self):
        validated = self.form_result
        self.emailer.send_mail(validated['email'], EMAIL,
                validated['subject'], validated['message'])
        return render('/contact_done.mako')
<!DOCTYPE HTML>
<html>
    <head>
        ${self.head_tags()}
        ...
    </head>
    <body>
        <div id="header">...</div>
        <div id="content">
            ${self.body()}
        </div>

        <div id="footer">...</div>

        <%include file="google_analytics.mako"/>
        ${self.foot_tags()}

    </body>
</html>
<%inherit file="/base.mako" />

<%def name="head_tags()">
<title>How Old Is My Kid?</title>
</%def>

<h2>Contact Us</h2>

<p>Suggest a new feature, let us know how we're doing, or just say hi.</p>

<form method="POST" action="/contact" id="contact-form">
    <p><label for="email">Email:</label> <input type="text" name="email"
id="email" /></p>
    <p><label for="subject">Subject:</label> <input type="text"
name="subject" id="subject" /></p>
    <p><label for="message">Message:</label><br />
<textarea name="message" id="message"></textarea></p>
    <p><input type="submit" value="Submit" /></p>
</form>

<%def name="foot_tags()">
<script type="text/javascript">
$(document).ready(function() {
    $("button, input:submit").button();
});
</script>
</%def>
Django
• https://www.djangoproject.com/
• Full stack/harder to replace components
• Lots of reusable apps
• Admin interface
• Lots of deployment options (Google)
• Not dead
from django.conf.urls.defaults import patterns, url

urlpatterns = patterns('',
    url(r'^/$', 'howoldismykid.views.main',
            name='main'),
    url(r'^/contact/$', 'howoldismykid.views.contact',
            name='contact'),
)
from django.shortcuts import render

def main(request):
    return render(request, 'main.html')
from django import forms


class ContactForm(forms.Form):

    email = forms.EmailField(label='Email Address')
    subject = forms.CharField(label='Subject')
    message = forms.CharField(label='Message',
            widget=forms.Textarea)
from contact.forms import ContactForm
from django.shortcuts import render

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            emailer = 
                    Emailer(SMTP, USER, PW, FAKE_EMAIL)
            emailer.send_mail(
                    form.cleaned_data['email'], EMAIL,
                    form.cleaned_data['subject'],
                    form.cleaned_data['message'])
            return render(request, 'contact_done.html')
    else:
        form = ContactForm()

    return render(request, 'contact.html',
        {'form': form })
<!DOCTYPE HTML>
<html>
    <head>
        {% block head_tags %}...{% endblock %}
        ...
    </head>
    <body>
        <div id="header">...</header>
        <div id="content">
            {% block content %}It goes here.{% endblock %}
        </div>

        <div id="footer">...</div>

        {% include "google_analytics.html" %}
        {% block foot_tags %}{% endblock %}

    </body>
</html>
{% extends 'base.html' %}

{% block head_tags %}
<title>How Old Is My Kid?</title>
{% endblock %}

{% block content %}
<h2>Contact Us</h2>

<p>Suggest a new feature, let us know how we're doing, or just say hi.</p>

<form method="POST" action="/contact" id="contact-form">
    {% csrf_token %}
    {{ form.as_p }}
    <p><input type="submit" value="Submit" /></p>
</form>
{% endblock %}

{% block foot_tags %}
<script type="text/javascript">
$(document).ready(function() {
    $("button, input:submit").button();
});
</script>
{% endblock %}
The Culture
Planet Python

• http://planet.python.org/
• Aggregate feed of Python blogs
• Great way to follow what's going on
• Minimize newsgroup/mailing list burdens
• Easy to be included
The Python Ecosystem

• http://mirnazim.org/writings/python-
  ecosystem-introduction/
• Great introduction to the Python ecosystem
• Everything you need to get up and running
The Hitchhiker’s Guide

• http://docs.python-guide.org/
• Opinionated advice about using Python
• Basics
• Scenario-specific details and
  recommendations
PyMotW
• Explored a different standard library module
  every week
• Examples, examples, examples
• http://www.doughellmann.com/PyMOTW/
• The Python Standard Library by Example
  http://www.doughellmann.com/books/byexample/
Podcasts
• http://www.radiofreepython.com/
• http://frompythonimportpodcast.com/
• http://djangodose.com/
• http://advocacy.python.org/podcasts/
• http://www.awaretek.com/python/
• Start your own! Be the change you want...
PyOhio

• Free as in $0.00
• Columbus, Ohio
• Last weekend in July
• http://pyohio.org
PyCon
• Great people
• Great vibe
• All volunteer–personal ownership
• Video! http://pycon.blip.tv/
• 2012 & 2013: Santa Clara
• 2014 & 2015: Montreal
TiP BoF

• Testing in Python Birds of a Feather
• Lightning Talks
• Heckling...
...and goats
The Zen


• Guiding principles
• Sage advice
• >>>   import this
The Zen
• Beautiful is better than ugly.   • Readability counts.
• Explicit is better than          • Special cases aren't special
   implicit.                          enough to break the rules.

• Simple is better than            • Although practicality beats
   complex.                           purity.

• Complex is better than           • Errors should never pass
   complicated.                       silently.

• Flat is better than nested.      • Unless explicitly silenced.
• Sparse is better than dense.
The Zen
• In the face of ambiguity,    • Although never is often
   refuse the temptation to       better than right now.
   guess.
                               • If the implementation is
• There should be one–            hard to explain, it's a bad
   and preferably only one–       idea.
   obvious way to do it.
                               • If the implementation is
• Although that way may not       easy to explain, it may be a
   be obvious at first unless      good idea.
   you're Dutch.
                               • Namespaces are one
• Now is better than never.       honking great idea -- let's
                                  do more of those!
What About You?
Fin

• Twitter: @mpirnat
• Blog: http://mike.pirnat.com
• Win a special prize–name all the movies
• Thanks for coming!

Contenu connexe

Tendances

PHP 7 – What changed internally?
PHP 7 – What changed internally?PHP 7 – What changed internally?
PHP 7 – What changed internally?Nikita Popov
 
Haskell in the Real World
Haskell in the Real WorldHaskell in the Real World
Haskell in the Real Worldosfameron
 
Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Fwdays
 
Fantastic DSL in Python
Fantastic DSL in PythonFantastic DSL in Python
Fantastic DSL in Pythonkwatch
 
PHP Performance Trivia
PHP Performance TriviaPHP Performance Trivia
PHP Performance TriviaNikita Popov
 
Python于Web 2.0网站的应用 - QCon Beijing 2010
Python于Web 2.0网站的应用 - QCon Beijing 2010Python于Web 2.0网站的应用 - QCon Beijing 2010
Python于Web 2.0网站的应用 - QCon Beijing 2010Qiangning Hong
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)James Titcumb
 
Active Support Core Extensions (1)
Active Support Core Extensions (1)Active Support Core Extensions (1)
Active Support Core Extensions (1)RORLAB
 
Groovy presentation
Groovy presentationGroovy presentation
Groovy presentationManav Prasad
 
Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?Nikita Popov
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Jeff Carouth
 
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Charles Nutter
 
Proxies are Awesome!
Proxies are Awesome!Proxies are Awesome!
Proxies are Awesome!Brendan Eich
 
"How was it to switch from beautiful Perl to horrible JavaScript", Viktor Tur...
"How was it to switch from beautiful Perl to horrible JavaScript", Viktor Tur..."How was it to switch from beautiful Perl to horrible JavaScript", Viktor Tur...
"How was it to switch from beautiful Perl to horrible JavaScript", Viktor Tur...Fwdays
 
What's new in PHP 8.0?
What's new in PHP 8.0?What's new in PHP 8.0?
What's new in PHP 8.0?Nikita Popov
 
Pig Introduction to Pig
Pig Introduction to PigPig Introduction to Pig
Pig Introduction to PigChris Wilkes
 
Opaque Pointers Are Coming
Opaque Pointers Are ComingOpaque Pointers Are Coming
Opaque Pointers Are ComingNikita Popov
 
Interceptors: Into the Core of Pedestal
Interceptors: Into the Core of PedestalInterceptors: Into the Core of Pedestal
Interceptors: Into the Core of PedestalKent Ohashi
 
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...takeoutweight
 

Tendances (20)

PHP 7 – What changed internally?
PHP 7 – What changed internally?PHP 7 – What changed internally?
PHP 7 – What changed internally?
 
Haskell in the Real World
Haskell in the Real WorldHaskell in the Real World
Haskell in the Real World
 
Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"
 
Fantastic DSL in Python
Fantastic DSL in PythonFantastic DSL in Python
Fantastic DSL in Python
 
PHP Performance Trivia
PHP Performance TriviaPHP Performance Trivia
PHP Performance Trivia
 
Python于Web 2.0网站的应用 - QCon Beijing 2010
Python于Web 2.0网站的应用 - QCon Beijing 2010Python于Web 2.0网站的应用 - QCon Beijing 2010
Python于Web 2.0网站的应用 - QCon Beijing 2010
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
 
Active Support Core Extensions (1)
Active Support Core Extensions (1)Active Support Core Extensions (1)
Active Support Core Extensions (1)
 
Groovy presentation
Groovy presentationGroovy presentation
Groovy presentation
 
Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?
 
Scala vs Ruby
Scala vs RubyScala vs Ruby
Scala vs Ruby
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
 
Proxies are Awesome!
Proxies are Awesome!Proxies are Awesome!
Proxies are Awesome!
 
"How was it to switch from beautiful Perl to horrible JavaScript", Viktor Tur...
"How was it to switch from beautiful Perl to horrible JavaScript", Viktor Tur..."How was it to switch from beautiful Perl to horrible JavaScript", Viktor Tur...
"How was it to switch from beautiful Perl to horrible JavaScript", Viktor Tur...
 
What's new in PHP 8.0?
What's new in PHP 8.0?What's new in PHP 8.0?
What's new in PHP 8.0?
 
Pig Introduction to Pig
Pig Introduction to PigPig Introduction to Pig
Pig Introduction to Pig
 
Opaque Pointers Are Coming
Opaque Pointers Are ComingOpaque Pointers Are Coming
Opaque Pointers Are Coming
 
Interceptors: Into the Core of Pedestal
Interceptors: Into the Core of PedestalInterceptors: Into the Core of Pedestal
Interceptors: Into the Core of Pedestal
 
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...
Haste (Same Language, Multiple Platforms) and Tagless Final Style (Same Synta...
 

En vedette

Shiny, Let’s Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulner...
Shiny, Let’s Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulner...Shiny, Let’s Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulner...
Shiny, Let’s Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulner...Michael Pirnat
 
Climbing the Abstract Syntax Tree (Bulgaria PHP 2016)
Climbing the Abstract Syntax Tree (Bulgaria PHP 2016)Climbing the Abstract Syntax Tree (Bulgaria PHP 2016)
Climbing the Abstract Syntax Tree (Bulgaria PHP 2016)James Titcumb
 
Hugging Abstract Syntax Trees: A Pythonic Love Story (OSDC 2010)
Hugging Abstract Syntax Trees: A Pythonic Love Story (OSDC 2010)Hugging Abstract Syntax Trees: A Pythonic Love Story (OSDC 2010)
Hugging Abstract Syntax Trees: A Pythonic Love Story (OSDC 2010)Tom Lee
 
A Few of My Favorite Things
A Few of My Favorite ThingsA Few of My Favorite Things
A Few of My Favorite Thingsstumpteacher
 
Jack's Favorite Things
Jack's Favorite ThingsJack's Favorite Things
Jack's Favorite ThingsSimonRoyals
 
Favorite things sample
Favorite things sampleFavorite things sample
Favorite things samplehillaryalex
 
Kristina’s favorite things
Kristina’s favorite thingsKristina’s favorite things
Kristina’s favorite thingsGreg Miller
 
Tina’s Favorite Things
Tina’s Favorite ThingsTina’s Favorite Things
Tina’s Favorite ThingsTina Merritt
 
My favourite thing
My favourite thingMy favourite thing
My favourite thinglffl
 
Sam's Favorite Things
Sam's Favorite ThingsSam's Favorite Things
Sam's Favorite ThingsSimonRoyals
 
Declarative Syntax Definition - Grammars and Trees
Declarative Syntax Definition - Grammars and TreesDeclarative Syntax Definition - Grammars and Trees
Declarative Syntax Definition - Grammars and TreesGuido Wachsmuth
 
Emmy’s favorite things
Emmy’s favorite thingsEmmy’s favorite things
Emmy’s favorite thingsguest8bf0bb
 

En vedette (20)

Shiny, Let’s Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulner...
Shiny, Let’s Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulner...Shiny, Let’s Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulner...
Shiny, Let’s Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulner...
 
Climbing the Abstract Syntax Tree (Bulgaria PHP 2016)
Climbing the Abstract Syntax Tree (Bulgaria PHP 2016)Climbing the Abstract Syntax Tree (Bulgaria PHP 2016)
Climbing the Abstract Syntax Tree (Bulgaria PHP 2016)
 
Hugging Abstract Syntax Trees: A Pythonic Love Story (OSDC 2010)
Hugging Abstract Syntax Trees: A Pythonic Love Story (OSDC 2010)Hugging Abstract Syntax Trees: A Pythonic Love Story (OSDC 2010)
Hugging Abstract Syntax Trees: A Pythonic Love Story (OSDC 2010)
 
A Few of My Favorite Things
A Few of My Favorite ThingsA Few of My Favorite Things
A Few of My Favorite Things
 
Jack's Favorite Things
Jack's Favorite ThingsJack's Favorite Things
Jack's Favorite Things
 
My favorite things
My favorite thingsMy favorite things
My favorite things
 
Favorite things sample
Favorite things sampleFavorite things sample
Favorite things sample
 
Yaru,unit1animals
Yaru,unit1animalsYaru,unit1animals
Yaru,unit1animals
 
Kristina’s favorite things
Kristina’s favorite thingsKristina’s favorite things
Kristina’s favorite things
 
Tina’s Favorite Things
Tina’s Favorite ThingsTina’s Favorite Things
Tina’s Favorite Things
 
Clothes
ClothesClothes
Clothes
 
Clothes
ClothesClothes
Clothes
 
My favourite thing
My favourite thingMy favourite thing
My favourite thing
 
Game favorite clothes
Game favorite clothesGame favorite clothes
Game favorite clothes
 
Aula 2
Aula 2Aula 2
Aula 2
 
Clothes
ClothesClothes
Clothes
 
Sam's Favorite Things
Sam's Favorite ThingsSam's Favorite Things
Sam's Favorite Things
 
Declarative Syntax Definition - Grammars and Trees
Declarative Syntax Definition - Grammars and TreesDeclarative Syntax Definition - Grammars and Trees
Declarative Syntax Definition - Grammars and Trees
 
Emmy’s favorite things
Emmy’s favorite thingsEmmy’s favorite things
Emmy’s favorite things
 
My favorite things
My favorite thingsMy favorite things
My favorite things
 

Similaire à A Few of My Favorite (Python) Things

Stupid Awesome Python Tricks
Stupid Awesome Python TricksStupid Awesome Python Tricks
Stupid Awesome Python TricksBryan Helmig
 
Python-GTK
Python-GTKPython-GTK
Python-GTKYuren Ju
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPythonByterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPythonakaptur
 
Idioms in swift 2016 05c
Idioms in swift 2016 05cIdioms in swift 2016 05c
Idioms in swift 2016 05cKaz Yoshikawa
 
EcmaScript unchained
EcmaScript unchainedEcmaScript unchained
EcmaScript unchainedEduard Tomàs
 
python beginner talk slide
python beginner talk slidepython beginner talk slide
python beginner talk slidejonycse
 
An overview of Python 2.7
An overview of Python 2.7An overview of Python 2.7
An overview of Python 2.7decoupled
 
GE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python ProgrammingGE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python ProgrammingMuthu Vinayagam
 
Python GTK (Hacking Camp)
Python GTK (Hacking Camp)Python GTK (Hacking Camp)
Python GTK (Hacking Camp)Yuren Ju
 
Introduction to Python
Introduction to PythonIntroduction to Python
Introduction to PythonUC San Diego
 
Thinking in Functions: Functional Programming in Python
Thinking in Functions: Functional Programming in PythonThinking in Functions: Functional Programming in Python
Thinking in Functions: Functional Programming in PythonAnoop Thomas Mathew
 
Google Go For Ruby Hackers
Google Go For Ruby HackersGoogle Go For Ruby Hackers
Google Go For Ruby HackersEleanor McHugh
 
T3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmerT3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmerDavid Muñoz Díaz
 
The Vanishing Pattern: from iterators to generators in Python
The Vanishing Pattern: from iterators to generators in PythonThe Vanishing Pattern: from iterators to generators in Python
The Vanishing Pattern: from iterators to generators in PythonOSCON Byrum
 

Similaire à A Few of My Favorite (Python) Things (20)

Stupid Awesome Python Tricks
Stupid Awesome Python TricksStupid Awesome Python Tricks
Stupid Awesome Python Tricks
 
Python-GTK
Python-GTKPython-GTK
Python-GTK
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
Python Puzzlers
Python PuzzlersPython Puzzlers
Python Puzzlers
 
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPythonByterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
Byterun, a Python bytecode interpreter - Allison Kaptur at NYCPython
 
Intro to Python
Intro to PythonIntro to Python
Intro to Python
 
Idioms in swift 2016 05c
Idioms in swift 2016 05cIdioms in swift 2016 05c
Idioms in swift 2016 05c
 
EcmaScript unchained
EcmaScript unchainedEcmaScript unchained
EcmaScript unchained
 
python beginner talk slide
python beginner talk slidepython beginner talk slide
python beginner talk slide
 
An overview of Python 2.7
An overview of Python 2.7An overview of Python 2.7
An overview of Python 2.7
 
A tour of Python
A tour of PythonA tour of Python
A tour of Python
 
GE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python ProgrammingGE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python Programming
 
Python GTK (Hacking Camp)
Python GTK (Hacking Camp)Python GTK (Hacking Camp)
Python GTK (Hacking Camp)
 
Introduction to Python
Introduction to PythonIntroduction to Python
Introduction to Python
 
Python crush course
Python crush coursePython crush course
Python crush course
 
Thinking in Functions: Functional Programming in Python
Thinking in Functions: Functional Programming in PythonThinking in Functions: Functional Programming in Python
Thinking in Functions: Functional Programming in Python
 
Python 1
Python 1Python 1
Python 1
 
Google Go For Ruby Hackers
Google Go For Ruby HackersGoogle Go For Ruby Hackers
Google Go For Ruby Hackers
 
T3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmerT3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmer
 
The Vanishing Pattern: from iterators to generators in Python
The Vanishing Pattern: from iterators to generators in PythonThe Vanishing Pattern: from iterators to generators in Python
The Vanishing Pattern: from iterators to generators in Python
 

Dernier

Where developers are challenged, what developers want and where DevEx is going
Where developers are challenged, what developers want and where DevEx is goingWhere developers are challenged, what developers want and where DevEx is going
Where developers are challenged, what developers want and where DevEx is goingFrancesco Corti
 
LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0DanBrown980551
 
Planetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile BrochurePlanetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile BrochurePlanetek Italia Srl
 
Flow Control | Block Size | ST Min | First Frame
Flow Control | Block Size | ST Min | First FrameFlow Control | Block Size | ST Min | First Frame
Flow Control | Block Size | ST Min | First FrameKapil Thakar
 
Patch notes explaining DISARM Version 1.4 update
Patch notes explaining DISARM Version 1.4 updatePatch notes explaining DISARM Version 1.4 update
Patch notes explaining DISARM Version 1.4 updateadam112203
 
How to become a GDSC Lead GDSC MI AOE.pptx
How to become a GDSC Lead GDSC MI AOE.pptxHow to become a GDSC Lead GDSC MI AOE.pptx
How to become a GDSC Lead GDSC MI AOE.pptxKaustubhBhavsar6
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfCheryl Hung
 
Explore the UiPath Community and ways you can benefit on your journey to auto...
Explore the UiPath Community and ways you can benefit on your journey to auto...Explore the UiPath Community and ways you can benefit on your journey to auto...
Explore the UiPath Community and ways you can benefit on your journey to auto...DianaGray10
 
Oracle Database 23c Security New Features.pptx
Oracle Database 23c Security New Features.pptxOracle Database 23c Security New Features.pptx
Oracle Database 23c Security New Features.pptxSatishbabu Gunukula
 
TrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie WorldTrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie WorldTrustArc
 
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptxEmil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptxNeo4j
 
Stobox 4: Revolutionizing Investment in Real-World Assets Through Tokenization
Stobox 4: Revolutionizing Investment in Real-World Assets Through TokenizationStobox 4: Revolutionizing Investment in Real-World Assets Through Tokenization
Stobox 4: Revolutionizing Investment in Real-World Assets Through TokenizationStobox
 
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedIn
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedInOutage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedIn
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedInThousandEyes
 
CyberSecurity - Computers In Libraries 2024
CyberSecurity - Computers In Libraries 2024CyberSecurity - Computers In Libraries 2024
CyberSecurity - Computers In Libraries 2024Brian Pichman
 
AI Workshops at Computers In Libraries 2024
AI Workshops at Computers In Libraries 2024AI Workshops at Computers In Libraries 2024
AI Workshops at Computers In Libraries 2024Brian Pichman
 
Technical SEO for Improved Accessibility WTS FEST
Technical SEO for Improved Accessibility  WTS FESTTechnical SEO for Improved Accessibility  WTS FEST
Technical SEO for Improved Accessibility WTS FESTBillieHyde
 
Keep Your Finger on the Pulse of Your Building's Performance with IES Live
Keep Your Finger on the Pulse of Your Building's Performance with IES LiveKeep Your Finger on the Pulse of Your Building's Performance with IES Live
Keep Your Finger on the Pulse of Your Building's Performance with IES LiveIES VE
 
Novo Nordisk's journey in developing an open-source application on Neo4j
Novo Nordisk's journey in developing an open-source application on Neo4jNovo Nordisk's journey in developing an open-source application on Neo4j
Novo Nordisk's journey in developing an open-source application on Neo4jNeo4j
 
EMEA What is ThousandEyes? Webinar
EMEA What is ThousandEyes? WebinarEMEA What is ThousandEyes? Webinar
EMEA What is ThousandEyes? WebinarThousandEyes
 
From the origin to the future of Open Source model and business
From the origin to the future of  Open Source model and businessFrom the origin to the future of  Open Source model and business
From the origin to the future of Open Source model and businessFrancesco Corti
 

Dernier (20)

Where developers are challenged, what developers want and where DevEx is going
Where developers are challenged, what developers want and where DevEx is goingWhere developers are challenged, what developers want and where DevEx is going
Where developers are challenged, what developers want and where DevEx is going
 
LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0LF Energy Webinar - Unveiling OpenEEMeter 4.0
LF Energy Webinar - Unveiling OpenEEMeter 4.0
 
Planetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile BrochurePlanetek Italia Srl - Corporate Profile Brochure
Planetek Italia Srl - Corporate Profile Brochure
 
Flow Control | Block Size | ST Min | First Frame
Flow Control | Block Size | ST Min | First FrameFlow Control | Block Size | ST Min | First Frame
Flow Control | Block Size | ST Min | First Frame
 
Patch notes explaining DISARM Version 1.4 update
Patch notes explaining DISARM Version 1.4 updatePatch notes explaining DISARM Version 1.4 update
Patch notes explaining DISARM Version 1.4 update
 
How to become a GDSC Lead GDSC MI AOE.pptx
How to become a GDSC Lead GDSC MI AOE.pptxHow to become a GDSC Lead GDSC MI AOE.pptx
How to become a GDSC Lead GDSC MI AOE.pptx
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
Explore the UiPath Community and ways you can benefit on your journey to auto...
Explore the UiPath Community and ways you can benefit on your journey to auto...Explore the UiPath Community and ways you can benefit on your journey to auto...
Explore the UiPath Community and ways you can benefit on your journey to auto...
 
Oracle Database 23c Security New Features.pptx
Oracle Database 23c Security New Features.pptxOracle Database 23c Security New Features.pptx
Oracle Database 23c Security New Features.pptx
 
TrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie WorldTrustArc Webinar - How to Live in a Post Third-Party Cookie World
TrustArc Webinar - How to Live in a Post Third-Party Cookie World
 
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptxEmil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
Emil Eifrem at GraphSummit Copenhagen 2024 - The Art of the Possible.pptx
 
Stobox 4: Revolutionizing Investment in Real-World Assets Through Tokenization
Stobox 4: Revolutionizing Investment in Real-World Assets Through TokenizationStobox 4: Revolutionizing Investment in Real-World Assets Through Tokenization
Stobox 4: Revolutionizing Investment in Real-World Assets Through Tokenization
 
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedIn
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedInOutage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedIn
Outage Analysis: March 5th/6th 2024 Meta, Comcast, and LinkedIn
 
CyberSecurity - Computers In Libraries 2024
CyberSecurity - Computers In Libraries 2024CyberSecurity - Computers In Libraries 2024
CyberSecurity - Computers In Libraries 2024
 
AI Workshops at Computers In Libraries 2024
AI Workshops at Computers In Libraries 2024AI Workshops at Computers In Libraries 2024
AI Workshops at Computers In Libraries 2024
 
Technical SEO for Improved Accessibility WTS FEST
Technical SEO for Improved Accessibility  WTS FESTTechnical SEO for Improved Accessibility  WTS FEST
Technical SEO for Improved Accessibility WTS FEST
 
Keep Your Finger on the Pulse of Your Building's Performance with IES Live
Keep Your Finger on the Pulse of Your Building's Performance with IES LiveKeep Your Finger on the Pulse of Your Building's Performance with IES Live
Keep Your Finger on the Pulse of Your Building's Performance with IES Live
 
Novo Nordisk's journey in developing an open-source application on Neo4j
Novo Nordisk's journey in developing an open-source application on Neo4jNovo Nordisk's journey in developing an open-source application on Neo4j
Novo Nordisk's journey in developing an open-source application on Neo4j
 
EMEA What is ThousandEyes? Webinar
EMEA What is ThousandEyes? WebinarEMEA What is ThousandEyes? Webinar
EMEA What is ThousandEyes? Webinar
 
From the origin to the future of Open Source model and business
From the origin to the future of  Open Source model and businessFrom the origin to the future of  Open Source model and business
From the origin to the future of Open Source model and business
 

A Few of My Favorite (Python) Things

  • 1. A Few of My Favorite Things Mike Pirnat • AG Interactive • CodeMash 2012
  • 2. A Few of My Favorite Things Mike Pirnat • AG Interactive • CodeMash 2012
  • 10. _ ( = 255, lambda V ,B,c :c and Y(V*V+B,B, c -1)if(abs(V)<6)else ( 2+c-4*abs(V)**-0.4)/i ) ;v, x=1500,1000;C=range(v*x );import struct;P=struct.pack;M, j ='<QIIHHHH',open('M.bmp','wb').write for X in j('BM'+P(M,v*x*3+26,26,12,v,x,1,24))or C: i ,Y=_;j(P('BBB',*(lambda T:(T*80+T**9 *i-950*T **99,T*70-880*T**18+701* T **9 ,T*i**(1-T**45*2)))(sum( [ Y(0,(A%3/3.+X%v+(X/v+ A/3/3.-x/2)/1j)*2.5 /x -2.7,i)**2 for A in C [:9]]) /9) ) ) http://preshing.com/20110926/high-resolution-mandelbrot-in-obfuscated-python
  • 12. The Interactive Shell $ python Python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05) [GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>>
  • 13. Docstrings... class Frobulator(object): """It frobulates things.""" def __init__(self, doohickey): """A Frobulator needs a doohickey.""" self.doohickey = doohickey def frobulate(self): """Frobulate ALL the things!""" print "Frobulating..." doodad = self.doohickey() return FrobulatedThing(doodad) class FrobulatedThing(object): """A thing which has been frobulated.""" def __init__(self, thing): """Make a thing into a frobulated thing.""" self.thing = thing
  • 14. ...and Help >>> help(Frobulator) Help on class Frobulator in module frobulator: class Frobulator(__builtin__.object) | It frobulates things. | | Methods defined here: | | __init__(self, doohickey) | A Frobulator needs a doohickey. | | frobulate(self) | Frobulate ALL the things! | ...
  • 15. Comprehensions • List comprehensions • Set comprehensions • Dictionary comprehensions • Generator expressions
  • 16. List Comprehensions x = [item for item in series] x = [do_something(item) for item in series if expression] things = [Thingy.from_data(x) for x in database_results] partiers = [x for x in codemashers if x.slides_done()]
  • 17. List Comprehensions booze = ['beer', 'wine', 'scotch', 'gin'] soft_drinks = ['water', 'soda', 'juice'] a = [(x, y) for x in booze for y in soft_drinks] [('beer', 'water'), ('beer', 'soda'), ('beer', 'juice'), ('wine', 'water'), ('wine', 'soda'), ('wine', 'juice'), ('scotch', 'water'), ('scotch', 'soda'), ('scotch', 'juice'), ('gin', 'water'), ('gin', 'soda'), ('gin', 'juice')]
  • 18. List Comprehensions b = [x for x in zip(booze, soft_drinks)] [('beer', 'water'), ('wine', 'soda'), ('scotch', 'juice')]
  • 19. Set Comprehensions s = {v for v in 'CODEMASH ROCKS' if v not in 'ABCD'} set([' ', 'E', 'H', 'K', 'M', 'O', 'S', 'R'])
  • 20. Dictionary Comprehensions d = {key: value for key, value in list_of_tuples} d = { 'Mike': 'Python', 'Jim': 'Ruby', 'Brad': 'UX', ... } d1 = {val: key for key, val in d.items()} {'Python': 'Mike', 'Ruby': 'Jim', 'UX': 'Brad', ...}
  • 21. Generators def f(how_many): for number in range(how_many): if number**2 > 3: yield number * 2 for number in f(5): print number 4 6 8
  • 22. Generator Expressions gen = (2*x for x in range(5) if x**2 > 3) for number in gen: print number 4 6 8
  • 23. Properties class Foo(object): def __init__(self, bar=42): self.set_bar(bar) def get_bar(self): return self.bar def set_bar(self, bar): self.bar = int(bar)
  • 24. Properties class Foo(object): def __init__(self, bar=42): self.bar = bar @property def bar(self): return self._bar @bar.setter def bar(self, x): self._bar = int(x)
  • 25. Properties class Foo(object): def __init__(self, bar=42): self.bar = bar @property def bar(self): return self._bar @bar.setter def bar(self, x): self._bar = int(x)
  • 26. Properties >>> foo = Foo() >>> foo.bar 42 >>> foo.bar = 'abc' Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 9, in bar ValueError: invalid literal for int() with base 10: 'abc'
  • 27. Decorators • That funny-looking @ thing • Similar to Java’s annotations • Replaces a function with a wrapper • Augment functionality in a reusable way
  • 28. Decorators def be_excellent(wrapped): def wrapper(*args, **kwargs): print "Be excellent to each other..." return wrapped(*args, **kwargs) return wrapper @be_excellent def party_on(who): print "...and party on, {0}!".format(who) >>> party_on('dudes') Be excellent to each other... ...and party on, dudes!
  • 29. Context Managers • That funny “with” thing • Simplify calling code that needs setup and teardown • Alternative to try/finally structures • Acquire locks, open and close files, do database transactions, etc.
  • 30. Before Context Managers frobulator = Frobulator(...) try: frobulator.frobulate() finally: frobulator.cleanup()
  • 31. After Context Managers with Frobulator(...) as frobulator: frobulator.frobulate()
  • 32. class Frobulator(object): def __init__(self, ...): ... def __enter__(self): print "Preparing to frobulate..." return self def __exit__(self, exc_type, exc_value, exc_tb): print "Frobulation complete!" def frobulate(self): print "Frobulating!" ...
  • 33. with Frobulator() as frobulator: frobulator.frobulate() Preparing to frobulate... Frobulating! Frobulation complete!
  • 34. import contextlib @contextlib.contextmanager def make_frobulator(): print "Preparing to frobulate..." yield Frobulator() print "Frobulation complete!" with make_frobulator() as frobulator: frobulator.frobulate() Preparing to frobulate... Frobulating! Frobulation complete!
  • 36. Itertools • Tools for iterating on sequences • Inspired by functional languages • Fast and memory efficient • Combine to express more complicated algorithms
  • 37. Itertools: chain from itertools import chain for x in chain([1, 2, 3], [42, 1138, 2112]): print x, 1 2 3 42 1138 2112
  • 38. Itertools: izip from itertools import izip for x in izip([1, 2, 3], [42, 1138, 2112]): print x, (1, 42) (2, 1138) (3, 2112)
  • 39. Itertools: islice from itertools import islice, count for x in islice(count(), 5): print x, for x in islice(count(), 5, 10): print x, for x in islice(count(), 0, 100, 10): print x, 0 1 2 3 4 5 6 7 8 9 0 10 20 30 40 50 60 70 80 90
  • 40. Itertools: islice from itertools import islice, count for x in islice(count(), 5): print x, for x in islice(count(), 5, 10): print x, for x in islice(count(), 0, 100, 10): print x, 0 1 2 3 4 5 6 7 8 9 0 10 20 30 40 50 60 70 80 90
  • 41. Itertools: imap from itertools import imap for thingy in imap(Thingy.from_data, database_results): ...
  • 42. Itertools: cycle from itertools import cycle for x in cycle(['wake up', 'meet Ned', 'romance Rita']): print x wake up meet Ned romance Rita wake up meet Ned romance Rita wake up meet Ned ...
  • 43. Itertools: repeat from itertools import repeat for x in repeat("stop hitting yourself", 5): print x stop hitting yourself stop hitting yourself stop hitting yourself stop hitting yourself stop hitting yourself
  • 44. Functools • Tools for manipulating functions • Partial • Wraps a callable with default arguments • Alternative to lambdas and closures
  • 45. Functools: Partial from functools import partial def f(a, b=2): print a, b f1 = partial(f, 'fixed_a') f2 = partial(f, b='fixed_b') >>> f1(b=1138) fixed_a 1138 >>> f2(1138) 1138 fixed_b
  • 46. Functools: Partial def category_is(category, item): categories = [x.lower() for x in item.categories] if category.lower() in categories: return True return False is_python = partial(category_is, 'python') is_cat_pictures = partial(category_is, 'catpix') ... python_posts = [item for item in blog_posts if is_python(item)] cat_posts = [item for item in blog_posts if is_cat_pictures(item)]
  • 47. Collections • Beyond the basic list, dict, tuple, and set... • Counter • Defaultdict • OrderedDict • Namedtuple • ...and more
  • 48. Counter counter = {} for char in "Hello there, CodeMash!": if char not in counter: counter[char] = 1 else: counter[char] += 1 print counter {'a': 1, ' ': 2, 'C': 1, 'e': 4, 'd': 1, 'H': 1, 'M': 1, 'l': 2, 'o': 2, ',': 1, 's': 1, 'r': 1, '!': 1, 't': 1, 'h': 2}
  • 49. Counter counter = {} for char in "Hello there, CodeMash!": if char not in counter: counter[char] = 1 else: counter[char] += 1 print counter {'a': 1, ' ': 2, 'C': 1, 'e': 4, 'd': 1, 'H': 1, 'M': 1, 'l': 2, 'o': 2, ',': 1, 's': 1, 'r': 1, '!': 1, 't': 1, 'h': 2}
  • 50. Counter from collections import Counter counter = Counter("Hello there, CodeMash!") print counter Counter({'e': 4, ' ': 2, 'l': 2, 'o': 2, 'h': 2, 'a': 1, 'C': 1, 'd': 1, 'H': 1, 'M': 1, ',': 1, 's': 1, 'r': 1, '!': 1, 't': 1})
  • 51. Counter from collections import Counter counter = Counter("Hello there, CodeMash!") print counter Counter({'e': 4, ' ': 2, 'l': 2, 'o': 2, 'h': 2, 'a': 1, 'C': 1, 'd': 1, 'H': 1, 'M': 1, ',': 1, 's': 1, 'r': 1, '!': 1, 't': 1})
  • 52. Namedtuple import math def distance(a, b): return math.sqrt( (a[0] - b[0])**2 + (a[1] - b[1])**2 + (a[2] - b[2])**2 ) a = (1, 2, 3) b = (-1, -2, 42) print distance(a, b) 39.25557285278104
  • 53. Namedtuple from collections import namedtuple Point = namedtuple('Point', 'x y z') def distance(a, b): return math.sqrt( (a.x - b.x)**2 + (a.y - b.y)**2 + (a.z - b.z)**2 ) a = Point(x=1, y=2, z=3) b = Point(-1, -2, 42) print distance(a, b) 39.25557285278104
  • 54. Difflib s1 = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus dui nunc, faucibus id ullamcorper eget, tempus vitae nisl. Donec quis semper risus. Curabitur sit amet tellus eget metus accumsan porta nec nec lorem. Ut vitae sem nisl. Praesent pulvinar feugiat nibh fringilla semper. Nullam cursus tempor lorem ut egestas. Nullam suscipit gravida turpis ac porttitor. Curabitur eleifend augue at risus commodo pretium. Aliquam eget magna risus, ut lobortis metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam non magna sit amet nulla porttitor molestie sit amet vel sem. Vestibulum sit amet nisl a velit adipiscing porta id non urna. Duis ullamcorper dictum ipsum sit amet congue. """
  • 55. Difflib s2 = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus dui nunc, faucibus id ullamcorper eget, tempus vitae nisl. Donec quis semper risus. Curabitur sit amet tellus eget metus accumsan porta nec nec lorem. Ut vitae sem nisl. Praesent pulvinar feugiat nibh fringilla semper. Nullam cursus tempor lorem ut egestas. Nullam suscipit gravida turpis ac porttitor. Curabitur eleifend augue at risus commodo pretium. Aliquam eget magna risus, ut lobortis montes. Cum sociis natoque penatibus et magnis dis parturient metus, nascetur ridiculus mus. Etiam non magna sit amet nulla porttitor molestie sit amet vel sem. Vestibulum sit amet nisl a velit adipiscing porta id non urna. Duis ullamcorper dictum ipsum sit amet congue. """
  • 56. Difflib import difflib differ = difflib.Differ() diff = differ.compare(s1.splitlines(), s2.splitlines()) print 'n'.join(diff)
  • 57. Difflib Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus dui nunc, faucibus id ullamcorper eget, tempus vitae nisl. Donec quis semper risus. Curabitur sit amet tellus eget metus accumsan porta nec nec lorem. Ut vitae sem nisl. Praesent pulvinar feugiat nibh fringilla semper. Nullam cursus tempor lorem ut egestas. Nullam suscipit gravida turpis ac porttitor. Curabitur eleifend augue at risus commodo pretium. Aliquam eget magna - risus, ut lobortis metus. Cum sociis natoque penatibus ? -- + risus, ut lobortis montes. Cum sociis natoque penatibus ? +++ - et magnis dis parturient montes, nascetur ridiculus mus. ? ^^ ^ + et magnis dis parturient metus, nascetur ridiculus mus. ? ^ ^ Etiam non magna sit amet nulla porttitor molestie sit amet vel sem. Vestibulum sit amet nisl a velit adipiscing porta id non urna. Duis ullamcorper dictum ipsum sit amet congue.
  • 58. Difflib diff = difflib.unified_diff( s1.splitlines(), s2.splitlines(), lineterm='') print 'n'.join(diff)
  • 59. Difflib --- +++ @@ -7,8 +7,8 @@ semper. Nullam cursus tempor lorem ut egestas. Nullam suscipit gravida turpis ac porttitor. Curabitur eleifend augue at risus commodo pretium. Aliquam eget magna -risus, ut lobortis metus. Cum sociis natoque penatibus -et magnis dis parturient montes, nascetur ridiculus mus. +risus, ut lobortis montes. Cum sociis natoque penatibus +et magnis dis parturient metus, nascetur ridiculus mus. Etiam non magna sit amet nulla porttitor molestie sit amet vel sem. Vestibulum sit amet nisl a velit adipiscing porta id non urna. Duis ullamcorper dictum
  • 60. Ast • Use Python to process abstract syntax trees of Python grammar • Helps introspect about what the current grammar looks like • Helps write secure code
  • 61. Ast # Danger: foo = eval(bar) # Safe: foo = ast.literal_eval(bar)
  • 62. Multiprocessing • Like threading, but with subprocesses • Local and remote concurrency • Spawn processes or entire pools • Communicate via queues or pipes • Shared state via shared memory or manager/server process
  • 63. import os from multiprocessing import Process def info(title): print title print 'parent process:', os.getppid() print 'process id:', os.getpid() def f(name): info('function f') print 'hello', name if __name__ == '__main__': info('main') p = Process(target=f, args=('world',)) p.start() p.join()
  • 64. $ python process.py main parent process: 18647 process id: 31317 ---------- function f parent process: 31317 process id: 31318 ---------- hello world
  • 65. import os from multiprocessing import Pool def g(x): info('function g('+str(x)+')') return x * x if __name__ == '__main__': info('main') pool = Pool(2) print pool.map(g, range(100))
  • 66. $ python process.py parent process: 31369 main parent process: 31369 module name: __main__ process id: 31370 parent process: 18647 process id: 31371 process id: 31369 ---------- ---------- ---------- function g(0) function g(4) module name: __main__ module name: __main__ parent process: 31369 parent process: 31369 process id: 31370 function g(14) ---------- process id: 31370 function g(1) module name: __main__ module name: __main__ ---------- parent process: 31369 parent process: 31369 process id: 31370 function g(5) ---------- process id: 31371 function g(13) module name: __main__ function g(2) module name: __main__ ... parent process: 31369 process id: 31370 [0, 1, 4, 9, 16, 25, ..., 8836, ---------- 9025, 9216, 9409, 9604, 9801] module name: __main__ function g(3) module name: __main__
  • 68. Third Party Packages • Most available on PyPI--http://pypi.python.org • pip install packagename • easy_install packagename
  • 69. Virtualenv • Makes an isolated Python environment • Don’t pollute your global site-packages • Insulates Python projects from one another • Don't have to be root
  • 70. Virtualenv $ virtualenv directory $ virtualenv --python=/path/to/specific/python directory $ cd directory $ . bin/activate $ easy_install whatever $ pip install whatever ...do stuff... $ deactivate
  • 71. Datetime and Dateutil • Python’s datetime provides date, time, datetime, and timedelta objects • Dateutil provides powerful extensions • Parsing • Olson-driven timezones • Recurrence
  • 72. Parsing >>> from dateutil.parser import parse >>> parse('01/01/2012') datetime.datetime(2012, 1, 1, 0, 0) >>> parse('2012-01-01') datetime.datetime(2012, 1, 1, 0, 0)
  • 73. Timezones >>> from dateutil import zoneinfo >>> zone = zoneinfo.gettz('US/Eastern') >>> zone tzfile('America/New_York') >>> zone2 = zoneinfo.gettz('US/Hawaii') >>> dt = datetime.now(zone) >>> dt datetime.datetime(2012, 1, 13, 13, 46, 54, 997825, tzinfo=tzfile('America/New_York')) >>> dt.astimezone(zone2) datetime.datetime(2012, 1, 13, 8, 46, 54, 997825, tzinfo=tzfile('Pacific/Honolulu'))
  • 74. Recurrence >>> from dateutil.rrule import rrule, YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY, BY_EASTER >>> rr = rrule(YEARLY, dtstart=datetime(1948, 2, 24)) >>> rr.after(datetime(2012, 1, 1)) datetime(2012, 2, 24, 0, 0) >>> rr.between(datetime(2010, 1, 1), datetime(2012, 1, 1)) [datetime(2010, 2, 24, 0, 0), datetime(2011, 2, 24, 0, 0)]
  • 75. howoldismykid.com def periods_between(freq, start_date, end_date):     # dateutil.rrule falls down for monthly recurrences where the start # date's day is greater than the number of days in a subsequent month # in the range; ie, when start date is 10/31/2010, and end date is # 3/13/2011, rrule's between will only produce 2 instances, 12/31 and # 1/31, rather than 4.     if freq == MONTHLY and start_date.day > 28:         start_date = datetime.datetime(start_date.year, start_date.month,                 28, start_date.hour, start_date.minute, start_date.second)     # Same problem but for "Pirates of Penzance" leap day birthdays...     elif freq == YEARLY and is_leap_day(start_date):         start_date = datetime.datetime(start_date.year, start_date.month,                 28, start_date.hour, start_date.minute, start_date.second)     rr = rrule(freq, dtstart=start_date)     periods = len(rr.between(start_date, end_date))     return periods
  • 76. howoldismykid.com >>> start_date = datetime(2007, 9, 10) >>> end_date = datetime(2012, 1, 13) >>> periods_between(YEARLY, start_date, end_date) 4 >>> periods_between(MONTHLY, start_date, end_date) 52 >>> periods_between(WEEKLY, start_date, end_date) 226 >>> periods_between(DAILY, start_date, end_date) 1585
  • 77. Nose • Find, run, and report results of test suites • Low-friction setup • Extendable with plugins (more later) • http://readthedocs.org/docs/nose/en/latest/
  • 78. Nose # test_foo.py def test_a_thing(): assert False def test_another_thing(): assert True
  • 79. Nose $ nosetests tests/test_foo.py F. ====================================================================== FAIL: test_foo.test_a_thing ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/mpirnat/Code/frobulator/lib/python2.7/site-packages/ nose-1.1.2-py2.7.egg/nose/case.py", line 197, in runTest self.test(*self.arg) File "/Users/mpirnat/Code/frobulator/src/frobulator/tests/test_foo.py", line 2, in test_a_thing assert False AssertionError ---------------------------------------------------------------------- Ran 2 tests in 0.001s FAILED (failures=1)
  • 80. Nose class TestWhenFrobulating(object): def setup(self): self.frobulator = Frobulator() self.frobulator.frobulate() def test_that_it_frobulated(self): assert self.frobulator.has_frobulated def teardown(self): self.frobulator.cleanup()
  • 82. Nose: Useful Flags • --processes=number • -x • --pdb • --pdb-failures • --failed
  • 83. Nose Plugins • Add custom behavior to your test run • Get coverage statistics (coverage) • Measure cleanliness with PEP-8 (tissue) • Emit human-readable spec-style results (pinocchio) • Or write your own...
  • 84. class TestGeneratesLotsOfFailures(object): def test_generates_failures(self): def _make_a_test(i): # start with some wins if i < 7: assert True # but then it hits the fan... elif i < 30: assert False # then be a little random elif i % 3 == 0: assert False else: assert True for i in range(50): yield _make_a_test, i
  • 85. $ nosetests test_epic_fail.py .......FFFFFFFFFFFFFFFFFFFFFFFF..F..F..F..F..F..F. [lots of test failure output; use your imagination...] -------------------------------------------------------- Ran 50 tests in 0.010s FAILED (errors=30)
  • 87. import os from nose.plugins import Plugin class F7U12(Plugin): name = 'f7u12' enabled = True def options(self, parser, env=os.environ): super(F7U12, self).options(parser, env=env) def configure(self, options, config): super(F7U12, self).configure(options, config) self.config = config if not self.enabled: return
  • 88. def setOutputStream(self, stream): self.stream = stream return self.stream def begin(self): self.failure_count = 0 def handleFailure(self, test, err): self.failure_count += 1 if self.failure_count < 8: self.stream.write('F') else: self.stream.write('U') return True
  • 89. $ nosetests --with-f7u12 test_epic_fail.py .......FFFFFFFFUUUUUUUUUUUUUUUU..U..U..U..U..U..U. [lots of test failure output; use your imagination...] -------------------------------------------------------- Ran 50 tests in 0.010s FAILED (errors=30)
  • 90. Mock • Mock object framework • Avoid writing custom stubs • Uses “Action/Assert” model (not “Record/ Replay”) • Can also patch out module and class attributes in the scope of a test • http://www.voidspace.org.uk/python/mock/
  • 91. Mock from mock import Mock foo = Mock() foo.bar() foo.bar.baz(42) foo.bar.baz.return_value = "whatever" assert foo.bar.called foo.bar.baz.assert_called_with(42)
  • 92. Mock class TestWhenFrobulating(object): def setup(self): self.doohickey = Mock() self.frobulator = Frobulator(self.doohickey) self.frobulator.frobulate() def test_it_uses_the_doohickey(self): assert self.doohickey.called
  • 93. Mock from mock import patch class TestWhenFrobulating(object): @patch('frobulator.DingleHopper') def setup(self, dingle_hopper_class): self.dingle_hopper = Mock() dingle_hopper_class.return_value = self.dingle_hopper self.frobulator = Frobulator() self.frobulator.frobulate() def test_it_uses_a_dingle_hopper(self): assert self.dingle_hopper.called
  • 94. Coverage • Measure coverage of your codebase during program execution • Integrates with several test runners to measure test coverage • http://nedbatchelder.com/code/coverage/
  • 95. #!/usr/bin/env python class Frobulator(object): """It frobulates things.""" def __init__(self, doohickey): """A Frobulator needs a doohickey.""" self.doohickey = doohickey def frobulate(self): """Frobulate ALL the things!""" print "Frobulating..." doodad = self.doohickey() return FrobulatedThing(doodad) class FrobulatedThing(object): """A thing which has been frobulated.""" def __init__(self, thing): """Make a thing into a frobulated thing.""" self.thing = thing if __name__ == '__main__': x = FrobulatedThing(42)
  • 96. #!/usr/bin/env python class Frobulator(object): """It frobulates things.""" def __init__(self, doohickey): """A Frobulator needs a doohickey.""" self.doohickey = doohickey def frobulate(self): """Frobulate ALL the things!""" print "Frobulating..." doodad = self.doohickey() return FrobulatedThing(doodad) class FrobulatedThing(object): """A thing which has been frobulated.""" def __init__(self, thing): """Make a thing into a frobulated thing.""" self.thing = thing if __name__ == '__main__': x = FrobulatedThing(42)
  • 97. $ coverage run frobulator.py $ coverage report -m Name Stmts Miss Cover Missing ------------------------------------------ frobulator 12 4 67% 8, 12-14
  • 98. from mock import Mock, patch from frobulator import Frobulator, FrobulatedThing class TestWhenFrobulating(object): def setup(self): self.doohickey = Mock() self.doohickey.return_value = 42 self.frobulator = Frobulator(self.doohickey) self.result = self.frobulator.frobulate() def test_it_uses_a_doohickey(self): assert self.doohickey.called def test_it_returns_a_frobulated_thing(self): assert isinstance(self.result, FrobulatedThing)
  • 99. $ nosetests --with-coverage --cover-package frobulator .. Name Stmts Miss Cover Missing ------------------------------------------ frobulator 12 1 92% 26 ------------------------------------------ Ran 2 tests in 0.008s OK
  • 100. Useful Flags • --cover-erase • --cover-inclusive • --cover-tests
  • 101. Lettuce • Like Cucumber • BDD test framework • Natural language augmented by code • Big wins pairing Devs + QA + Biz • http://lettuce.it/
  • 102. Lettuce Vocabulary • Features • Scenarios • Steps • World • Terrain
  • 103. Feature: The website has a homepage In order to demo Lettuce As a presenter I want to test the homepage of a website Scenario: Verify the site is up Given I access the url "http://localhost:8000/" Then I get a status "200"
  • 104. from lettuce import step, world from nose.tools import assert_equals import requests @step(r'I access the url "(.*)"') def access_url(step, url): world.response = requests.get(url) @step(r'I get a status "(.*)"') def get_status(step, expected_status): expected_status = int(expected_status) assert_equals(world.response.status_code, expected_status)
  • 105. Snake-Guice • Framework for Dependency Injection • Reduce coupling! • Improve testability! • http://code.google.com/p/snake-guice/
  • 106. Snake-Guice • Bind identifiers to things you want to inject • Decorate code with injection hints • Use injector to get instance with all dependencies resolved and injected • Construct with mocks in tests, minimize the need for patching
  • 107. Define the Identifier class IFrobulator(object): pass
  • 108. Decorate Your Code from snakeguice import inject class WankelRotator(object): @inject(frobulator=IFrobulator) def __init__(self, frobulator): self.frobulator = frobulator
  • 109. Decorate Your Code from snakeguice import inject class WankelRotator(object): @inject(frobulator=IFrobulator) def __init__(self, frobulator): self.frobulator = frobulator
  • 110. Configure Bindings from frobulator import Frobulator class BindingModule(object): def configure(self, binder): binder.bind(IFrobulator, to=Frobulator)
  • 111. Get an Instance from snakeguice import Injector import WankelRotator injector = Injector(BindingModule()) rotator = injector.get_instance(WankelRotator)
  • 112. Requests • A human-friendly alternative to urllib2 • Maturing rapidly • http://python-requests.org/
  • 113. Using Requests import requests # Authentication! r = requests.get('https://api.github.com', auth=('user', 'pass')) print r.status_code print r.headers['content-type']
  • 114. Using Requests # Posting name-value pair form data post_data = {'foo': 'bar', 'baz': 'quux', ...} r = requests.post(url, data=post_data) # Posting a glob of JSON r = requests.post(url, data=json.dumps(post_data)) # Multipart file attachment files = {'my_file.xls': open('my_file.xls', 'rb')} r = requests.post(url, files=files)
  • 115. Using Requests # Custom headers! headers = {'X-foo': 'bar'} r = requests.get(url, headers=headers) # Cookies! cookies = {'a_cookie': 'is delicious'} r = requests.get(url, cookies=cookies)
  • 116. Pylons • http://docs.pylonsproject.org/en/latest/docs/ pylons.html • MVCish web framework • Glues together several component projects • Can use your preferred components • Somewhat dead (evolved into Pyramid)
  • 117. Pylons • Request/response: webob • URL dispatch: routes • Input validation: formencode • Persistence/ORM: sqlalchemy • Session: beaker • Templates: mako
  • 118. from routes import Mapper def make_map(config): """Create, configure and return the routes Mapper""" map = Mapper(directory=config['pylons.paths']['controllers'], always_scan=config['debug']) ... map.connect('/', controller='main', action='index') map.connect('/contact', controller='contact', action='index', conditions={'method':'GET'}) map.connect('/contact', controller='contact', action='send', conditions={'method':'POST'}) return map
  • 119. from howoldismykid.lib.base import BaseController, render class MainController(BaseController): def index(self): # Return a rendered template return render('/main.mako')
  • 120. from formencode import Schema, validators class ContactForm(Schema): email = validators.Email(not_empty=True) subject = validators.String(not_empty=True) message = validators.String(not_empty=True)
  • 121. from pylons.decorators import validate from howoldismykid.lib.base import BaseController, render from howoldismykid.model.forms import ContactForm class ContactController(BaseController): def __init__(self, *args, **kwargs): BaseController.__init__(self, *args, **kwargs) self.emailer = Emailer(SMTP, USER, PW, FAKE_EMAIL) def index(self): # Return a rendered template return render('/contact.mako') @validate(schema=ContactForm(), form="index", prefix_error=False) def send(self): validated = self.form_result self.emailer.send_mail(validated['email'], EMAIL, validated['subject'], validated['message']) return render('/contact_done.mako')
  • 122. <!DOCTYPE HTML> <html> <head> ${self.head_tags()} ... </head> <body> <div id="header">...</div> <div id="content"> ${self.body()} </div> <div id="footer">...</div> <%include file="google_analytics.mako"/> ${self.foot_tags()} </body> </html>
  • 123. <%inherit file="/base.mako" /> <%def name="head_tags()"> <title>How Old Is My Kid?</title> </%def> <h2>Contact Us</h2> <p>Suggest a new feature, let us know how we're doing, or just say hi.</p> <form method="POST" action="/contact" id="contact-form"> <p><label for="email">Email:</label> <input type="text" name="email" id="email" /></p> <p><label for="subject">Subject:</label> <input type="text" name="subject" id="subject" /></p> <p><label for="message">Message:</label><br /> <textarea name="message" id="message"></textarea></p> <p><input type="submit" value="Submit" /></p> </form> <%def name="foot_tags()"> <script type="text/javascript"> $(document).ready(function() { $("button, input:submit").button(); }); </script> </%def>
  • 124. Django • https://www.djangoproject.com/ • Full stack/harder to replace components • Lots of reusable apps • Admin interface • Lots of deployment options (Google) • Not dead
  • 125. from django.conf.urls.defaults import patterns, url urlpatterns = patterns('', url(r'^/$', 'howoldismykid.views.main', name='main'), url(r'^/contact/$', 'howoldismykid.views.contact', name='contact'), )
  • 126. from django.shortcuts import render def main(request): return render(request, 'main.html')
  • 127. from django import forms class ContactForm(forms.Form): email = forms.EmailField(label='Email Address') subject = forms.CharField(label='Subject') message = forms.CharField(label='Message', widget=forms.Textarea)
  • 128. from contact.forms import ContactForm from django.shortcuts import render def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): emailer = Emailer(SMTP, USER, PW, FAKE_EMAIL) emailer.send_mail( form.cleaned_data['email'], EMAIL, form.cleaned_data['subject'], form.cleaned_data['message']) return render(request, 'contact_done.html') else: form = ContactForm() return render(request, 'contact.html', {'form': form })
  • 129. <!DOCTYPE HTML> <html> <head> {% block head_tags %}...{% endblock %} ... </head> <body> <div id="header">...</header> <div id="content"> {% block content %}It goes here.{% endblock %} </div> <div id="footer">...</div> {% include "google_analytics.html" %} {% block foot_tags %}{% endblock %} </body> </html>
  • 130. {% extends 'base.html' %} {% block head_tags %} <title>How Old Is My Kid?</title> {% endblock %} {% block content %} <h2>Contact Us</h2> <p>Suggest a new feature, let us know how we're doing, or just say hi.</p> <form method="POST" action="/contact" id="contact-form"> {% csrf_token %} {{ form.as_p }} <p><input type="submit" value="Submit" /></p> </form> {% endblock %} {% block foot_tags %} <script type="text/javascript"> $(document).ready(function() { $("button, input:submit").button(); }); </script> {% endblock %}
  • 132. Planet Python • http://planet.python.org/ • Aggregate feed of Python blogs • Great way to follow what's going on • Minimize newsgroup/mailing list burdens • Easy to be included
  • 133. The Python Ecosystem • http://mirnazim.org/writings/python- ecosystem-introduction/ • Great introduction to the Python ecosystem • Everything you need to get up and running
  • 134. The Hitchhiker’s Guide • http://docs.python-guide.org/ • Opinionated advice about using Python • Basics • Scenario-specific details and recommendations
  • 135. PyMotW • Explored a different standard library module every week • Examples, examples, examples • http://www.doughellmann.com/PyMOTW/ • The Python Standard Library by Example http://www.doughellmann.com/books/byexample/
  • 136. Podcasts • http://www.radiofreepython.com/ • http://frompythonimportpodcast.com/ • http://djangodose.com/ • http://advocacy.python.org/podcasts/ • http://www.awaretek.com/python/ • Start your own! Be the change you want...
  • 137. PyOhio • Free as in $0.00 • Columbus, Ohio • Last weekend in July • http://pyohio.org
  • 138. PyCon • Great people • Great vibe • All volunteer–personal ownership • Video! http://pycon.blip.tv/ • 2012 & 2013: Santa Clara • 2014 & 2015: Montreal
  • 139. TiP BoF • Testing in Python Birds of a Feather • Lightning Talks • Heckling...
  • 141. The Zen • Guiding principles • Sage advice • >>> import this
  • 142. The Zen • Beautiful is better than ugly. • Readability counts. • Explicit is better than • Special cases aren't special implicit. enough to break the rules. • Simple is better than • Although practicality beats complex. purity. • Complex is better than • Errors should never pass complicated. silently. • Flat is better than nested. • Unless explicitly silenced. • Sparse is better than dense.
  • 143. The Zen • In the face of ambiguity, • Although never is often refuse the temptation to better than right now. guess. • If the implementation is • There should be one– hard to explain, it's a bad and preferably only one– idea. obvious way to do it. • If the implementation is • Although that way may not easy to explain, it may be a be obvious at first unless good idea. you're Dutch. • Namespaces are one • Now is better than never. honking great idea -- let's do more of those!
  • 145. Fin • Twitter: @mpirnat • Blog: http://mike.pirnat.com • Win a special prize–name all the movies • Thanks for coming!