Awesome

mkupidura@future-processing.com

@__fwkz__

What makes Python awesome?

Winning features

  • indentation,

  • iterator protocol,

  • list comps, set comps, dict comps and genexps

  • generators,

  • decorators,

  • context menagers,

  • metaclasses,

  • Abstract Base Classes

Indentation

  • This is how we write our pseudo code
  • Clean and intuitive
  • Indentation never lies

Indentation

for (i=0; i<10; i++);
    printf("Nalesnikiii?!");
for i in xrange(10):
    print("Nalesnikiii?!")

Iterator protocol

EVERYWHERE

Iterables:

  • strings,
  • lists,
  • sets,
  • dicts,
  • files,
  • itertools,
  • ...

 

Things that consume iterators:

  • for-loops,
  • min(),
  • max(),
  • sorted(),
  • sum(),
  • set(),
  • list(),
  • tuple(),
  • dict(),
  • itertools
  • ...

Can be chained like UNIX pipes and filters

sorted(set('abracadabra'))

sorted(set(open('lista_wildsteina.txt')))

sum(shares*price for symbol, shares, price in port)
cat lista_widsteina.txt | sort | uniq

SELECT SUM(shares*price) from port;

list comprehensions

  • one of the most loved Python feature,

  • derived from mathematics notation,

  • clean and beautiful,

  • much flexible and expressive than map, filter, reduce...

#Sum of powers
new_list = []
for x in xrange(1000):
    new_list.append(x**2)
sum_of_powers = sum(new_list)

# list comps!
sum_of_powers = sum([x**2 for x in xrange(1000)])  

#Fresh fruits
fresh_fruits = []
for fruit in fruits:
    if not fruit.rotten:
        fresh_fruits.append(fruit)

# list comps!
fresh_fruits = [fruit for fruit in fruits if not fruit.rotten]

#Agent?
[line.upper() for line in open('lista_wildsteina.txt')
 if 'Kupidura' in line]

Generators

  • Easiest way to write iterator

  • Simple syntax, only adds the YIELD keyword

  • Remember state beetween invocations

  • ACCEPT INPUT!

#Build and return a list
def firstn(n):
    num, nums = 0, []
    while num < n:
        nums.append(num)
        num += 1
    return nums

sum_of_first_n = sum(firstn(1000000))

for x in firstn():
    # complicated processing

#a generator that yields items instead of returning a list
def firstn(n):
    num = 0
    while num < n:
        yield num
        num += 1

sum_of_first_n = sum(firstn(1000000))

for x in firstn():
    # complicated processing

Generators accept inputs!

class Malfunction(Exception):
    pass
 
def my_generator():
    print 'starting up'
    val = yield 1
    print 'got:', val
 
    val = yield 2
    print 'got:', val
 
    try:
        yield 3
    except Malfunction:
        print 'malfunction!'
 
    yield 4
    print 'done'
 
gen = my_generator()
print gen.next() # start the generator
print gen.send(10) # send the value 10
print gen.send(20) # send the value 20
print gen.throw(Malfunction()) # raise an exception inside the generator
 
try:
    gen.next()
except StopIteration:
    pass

Decorators

  • expressive,
  • easy on eyes,
  • works for functions, methods, classes,
  • extremly reusable
@dec2
@dec1
def func(arg1, arg2, ...):
    pass

#This is equivalent to:
def func(arg1, arg2, ...):
    pass

func = dec2(dec1(func))
from bottle import get, post, request 

@get('/login')
def login():
    return '''
        <form action="/login" method="post">
            Username: <input name="username" type="text" />
            Password: <input name="password" type="password" />
            <input value="Login" type="submit" />
        </form>
    '''

@post('/login')
def do_login():
    username = request.forms.get('username')
    password = request.forms.get('password')
    if check_login(username, password):
        return "<p>Your login information was correct.</p>"
    else:
        return "<p>Login failed.</p>"

Context managers

  • elegant resource management,

  • powerful tool for refactoring code,

  • factors-out common setup and teardown code

with open("lista_wildsteina.txt") as f:
    print f.read()

with locking:
    access_resource()

with ignore(OSError):
    os.remove(file)

formal way to define interfaces in Python, while staying true to the spirit of duck-typing 

Abstract Base Classes

allows to customize the behaviour of isinstance() and issubclass()

class Container:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __contains__(self, x):
        return False

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Container:
            if _hasattr(C, "__contains__"):
                return True
        return NotImplemented

class ContainAllTheThings(object):
    def __contains__(self, item):
        return True

print(issubclass(ContainAllTheThings, collections.Container))
# prints True
print(isinstance(ContainAllTheThings(), collections.Container))
# prints True

If you implement the right interface, you're a subclass! 

class PageHandler:
    """
    Base class for page object handlers
    """
    __metaclass__ = ABCMeta

    def __init__(self, driver, scenario):
        self.driver = driver
        self.scenario = scenario
        self.page_object = self.page_object(driver, scenario)

    @abstractproperty
    def page_object(self):
        """ Binds PageHandler to certain Page Object Model """

    @abstractmethod
    def execute(self):
        """ Execute Page Object handler. """

class LoginHandler(PageHandler):
    def do_something(self):
        pass

login = LoginHandler(driver, scenario)

"""
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class LoginHandler
with abstract methods execute, page_object
"""

Raymond Hettinger

@raymondh

"Please take this presentation and be me."

 

https://www.youtube.com/watch?v=NfngrdLv9ZQ

 

 

Awesome Python

By fwkz

Awesome Python

  • 1,315