SlideShare ist ein Scribd-Unternehmen logo
1 von 79
Downloaden Sie, um offline zu lesen
Elegant Solutions For Everyday
Python Problems
Nina Zakharenko
@nnja
bit.ly/elegant-python-ca
ℹ There are links in these slides. Follow along ^
This talk is for you if:
— You're an intermediate python programmer
— You're coming to python from another language
— You want to learn about fancy features like: magic
methods, iterators, decorators, and context managers
slides: bit.ly/elegant-python-ca
@nnja
What
is
elegant code?
@nnja
How do we make code elegant?
We pick the right tool for the job!
Resources for converting from Python 2 -> 3
Beauty is
in the eye of
the beholder
magic
methods
image source
You're used to implementing __str__ and __repr__ --but
there's a whole other world of powerful magic methods!
By implementing a few straightforward methods,
you can make your objects behave like built-ins such as:
— numbers
— lists
— dictionaries
— and more...
@nnja
class Money:
currency_rates = {
'$': 1,
'€': 0.88,
}
def __init__(self, symbol, amount):
self.symbol = symbol
self.amount = amount
def __repr__(self):
return '%s%.2f' % (self.symbol, self.amount)
@nnja
class Money:
currency_rates = {
'$': 1,
'€': 0.88,
}
def __init__(self, symbol, amount):
self.symbol = symbol
self.amount = amount
def __repr__(self):
return '%s%.2f' % (self.symbol, self.amount)
@nnja
class Money:
# defined currency_rates, __init__, and repr above...
def convert(self, other):
"""Convert other amount to our currency"""
new_amount = (
other.amount / self.currency_rates[other.symbol]
* self.currency_rates[self.symbol])
return Money(self.symbol, new_amount)
@nnja
__repr__ in action
>>> soda_cost = Money('$', 5.25)
>>> soda_cost
$5.25
>>> pizza_cost = Money('€', 7.99)
>>> pizza_cost
€7.99
@nnja
class Money:
def __add__(self, other):
""" Add 2 Money instances using '+' """
new_amount = self.amount + self.convert(other).amount
return Money(self.symbol, new_amount)
@nnja
>>> soda_cost = Money('$', 5.25)
>>> pizza_cost = Money('€', 7.99)
>>> soda_cost + pizza_cost
$14.33
More on Magic Methods: Dive into Python3 - Special Method Names
>>> soda_cost = Money('$', 5.25)
>>> pizza_cost = Money('€', 7.99)
>>> soda_cost + pizza_cost
$14.33
>>> pizza_cost + soda_cost
€12.61
More on Magic Methods: Dive into Python3 - Special Method Names
@nnja
some magic methods map to built-in functions
class Alphabet:
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def __len__(self):
return len(self.letters)
>>> my_alphabet = Alphabet()
>>> len(my_alphabet)
26
@nnja
custom
iterators
image source
Making classes iterable
— In order to be iterable, a class needs to implement
__iter__()
— __iter__() must return an iterator
— In order to be an iterator a class needs to implement
__next__() which must raise StopIteration when there
are no more items to return
or next() in python2
^ can be confusing at first, but remember these guidelines for making classesGreat explanation of iterable vs. iterator vs. generator
class IterableServer:
services = [
{'active': False, 'protocol': 'ftp', 'port': 21},
{'active': True, 'protocol': 'ssh', 'port': 22},
{'active': True, 'protocol': 'http', 'port': 21},
]
def __init__(self):
self.current_pos = 0
def __iter__(self): # can return self, because __next__ implemented
return self
def __next__(self):
while self.current_pos < len(self.services):
service = self.services[self.current_pos]
self.current_pos += 1
if service['active']:
return service['protocol'], service['port']
raise StopIteration
next = __next__ # optional python2 compatibility
@nnja
>>> for protocol, port in IterableServer():
print('service %s is running on port %d' % (protocol, port))
service ssh is running on port 22
service http is running on port 21
... not bad
@nnja
tip: use a generator
when your iterator doesn't need to
maintain a lot of state
@nnja
class Server:
services = [
{'active': False, 'protocol': 'ftp', 'port': 21},
{'active': True, 'protocol': 'ssh', 'port': 22},
{'active': True, 'protocol': 'http', 'port': 21},
]
def __iter__(self):
for service in self.services:
if service['active']:
yield service['protocol'], service['port']
@nnja
class Server:
services = [
{'active': False, 'protocol': 'ftp', 'port': 21},
{'active': True, 'protocol': 'ssh', 'port': 22},
{'active': True, 'protocol': 'http', 'port': 21},
]
def __iter__(self):
for service in self.services:
if service['active']:
yield service['protocol'], service['port']
@nnja
Why does this work?
use single parenthesis ( ) to create a generator
comprehension
^ technically, a generator expression but I like this term better, and so does Ned Batchelder
>>> my_gen = (num for num in range(1))
>>> my_gen
<generator object <genexpr> at 0x107581bf8>
@nnja
An iterator must implement __next__()
>>> next(my_gen) # remember __len__() mapped to built-in len()
0
and raise StopIteration when
there are no more elements
>>> next(my_gen)
... StopIteration Traceback (most recent call last)
For more tools for working with iterators, check out itertools
✨
Method
✨
Magic
@nnja
alias methods
class Word:
def __init__(self, word):
self.word = word
def __repr__(self):
return self.word
def __add__(self, other_word):
return Word('%s %s' % (self.word, other_word))
# Add an alias from method __add__ to the method concat
concat = __add__
@nnja
When we add an alias from __add__ to concat because
methods are just objects
>>> # remember, concat = __add__
>>> first_name = Word('Max')
>>> last_name = Word('Smith')
>>> first_name + last_name
Max Smith
>>> first_name.concat(last_name)
Max Smith
>>> Word.__add__ == Word.concat
True
@nnja
Dog class
>>> class Dog:
sound = 'Bark'
def speak(self):
print(self.sound + '!', self.sound + '!')
>>> my_dog = Dog()
>>> my_dog.speak()
Bark! Bark!
read the docs
getattr(object, name, default)
>>> class Dog:
sound = 'Bark'
def speak(self):
print(self.sound + '!', self.sound + '!')
>>> my_dog = Dog()
>>> my_dog.speak()
Bark! Bark!
>>> getattr(my_dog, 'speak')
<bound method Dog.speak of <__main__.Dog object at 0x10b145f28>>
>>> speak_method = getattr(my_dog, 'speak')
>>> speak_method()
Bark! Bark!
read the docs
getattr(object, name, default)
>>> class Dog:
sound = 'Bark'
def speak(self):
print(self.sound + '!', self.sound + '!')
>>> my_dog = Dog()
>>> my_dog.speak()
Bark! Bark!
>>> getattr(my_dog, 'speak')
<bound method Dog.speak of <__main__.Dog object at 0x10b145f28>>
>>> speak_method = getattr(my_dog, 'speak')
>>> speak_method()
Bark! Bark!
read the docs
Example: command line tool with dynamic commands
class Operations:
def say_hi(self, name):
print('Hello,', name)
def say_bye(self, name):
print ('Goodbye,', name)
def default(self, arg):
print ('This operation is not supported.')
if __name__ == '__main__':
operations = Operations()
# let's assume error handling
command, argument = input('> ').split()
getattr(operations, command, operations.default)(argument)
read the docs
Output
$ python getattr.py
> say_hi Nina
Hello, Nina
> blah blah
This operation is not supported.
✨
additional reading - inverse of getattr() is setattr()
functool.partial(func, *args, **kwargs)
— Return a new partial object which behaves like func
called with args & kwargs
— if more args are passed in, they are appended to args
— if more keyword arguments are passed in, they extend
and override kwargs
read the docs on partials
functool.partial(func, *args, **kwargs)
>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo
functools.partial(<class 'int'>, base=2)
>>> basetwo('10010')
18
read the docs on partials
library I
!
: github.com/jpaugh/agithub
agithub is a (badly named) REST API client with
transparent syntax which facilitates rapid prototyping
— on any REST API!
— Implemented in 400 lines.
— Add support for any REST API in ~30 lines of code.
— agithub knows everything it needs to about protocol
(REST, HTTP, TCP), but assumes nothing about your
upstream API.
@nnja
define endpoint url & other connection properties
class GitHub(API):
def __init__(self, token=None, *args, **kwargs):
props = ConnectionProperties(
api_url = kwargs.pop('api_url', 'api.github.com'))
self.setClient(Client(*args, **kwargs))
self.setConnectionProperties(props)
then, start using the API!
>>> gh = GitHub('token')
>>> status, data = gh.user.repos.get(visibility='public', sort='created')
>>> # ^ Maps to GET /user/repos
>>> data
... ['tweeter', 'snipey', '...']
github.com/jpaugh/agithub
black magic!
but, how?...
@nnja
class API:
def __getattr__(self, key):
return IncompleteRequest(self.client).__getattr__(key)
__getitem__ = __getattr__
class IncompleteRequest:
def __getattr__(self, key):
if key in self.client.http_methods:
htmlMethod = getattr(self.client, key)
return partial(htmlMethod, url=self.url)
else:
self.url += '/' + str(key)
return self
__getitem__ = __getattr__
class Client:
http_methods = ('get') # ...
def get(self, url, headers={}, **params):
return self.request('GET', url, None, headers)
github.com/jpaugh/agithub source: base.py
class API:
def __getattr__(self, key):
return IncompleteRequest(self.client).__getattr__(key)
__getitem__ = __getattr__
class IncompleteRequest:
def __getattr__(self, key):
if key in self.client.http_methods:
htmlMethod = getattr(self.client, key)
return partial(htmlMethod, url=self.url)
else:
self.url += '/' + str(key)
return self
__getitem__ = __getattr__
class Client:
http_methods = ('get') # ...
def get(self, url, headers={}, **params):
return self.request('GET', url, None, headers)
github.com/jpaugh/agithub source: base.py
class API:
def __getattr__(self, key):
return IncompleteRequest(self.client).__getattr__(key)
__getitem__ = __getattr__
class IncompleteRequest:
def __getattr__(self, key):
if key in self.client.http_methods:
htmlMethod = getattr(self.client, key)
return partial(htmlMethod, url=self.url)
else:
self.url += '/' + str(key)
return self
__getitem__ = __getattr__
class Client:
http_methods = ('get') # ...
def get(self, url, headers={}, **params):
return self.request('GET', url, None, headers)
github.com/jpaugh/agithub source: base.py
given a non-existant path:
>>> status, data = this.path.doesnt.exist.get()
>>> status
... 404
& because __getitem__ is aliased to __getattr__:
>>> owner, repo = 'nnja', 'tweeter'
>>> status, data = gh.repos[owner][repo].pulls.get()
>>> # ^ Maps to GET /repos/nnja/tweeter/pulls
>>> data
.... # {....}
github.com/jpaugh/agithub
Context
Managers
& new in python 3: async context managers
When should I use one?
Need to perform an action before and/or after an
operation.
Common scenarios:
— Closing a resource after you're done with it (file,
network connection)
— Perform cleanup before/after a function call
@nnja
Example Problem: Feature Flags
Turn features of your application on and off easily.
Uses of feature flags:
— A/B Testing
— Rolling Releases
— Show Beta version to users opted-in to Beta Testing
Program
More on Feature Flags
Example - FeatureFlags Class
class FeatureFlags:
""" Example class which stores Feature Flags and their state. """
SHOW_BETA = 'Show Beta version of Home Page'
flags = {
SHOW_BETA: True
}
@classmethod
def is_on(cls, name):
return cls.flags[name]
@classmethod
def toggle(cls, name, on):
cls.flags[name] = on
feature_flags = FeatureFlags()
@nnja
How do we temporarily turn features on and off when
testing flags?
Want:
with feature_flag(FeatureFlags.SHOW_BETA):
assert '/beta' == get_homepage_url()
@nnja
Using Magic Methods __enter__ and __exit__
class feature_flag:
""" Implementing a Context Manager using Magic Methods """
def __init__(self, name, on=True):
self.name = name
self.on = on
self.old_value = feature_flags.is_on(name)
def __enter__(self):
feature_flags.toggle(self.name, self.on)
def __exit__(self, *args):
feature_flags.toggle(self.name, self.old_value)
See: contextlib.contextmanager
The be!er way: using the contextmanager decorator
from contextlib import contextmanager
@contextmanager
def feature_flag(name, on=True):
old_value = feature_flags.is_on(name)
feature_flags.toggle(name, on)
yield
feature_flags.toggle(name, old_value)
See: contextlib.contextmanager
The be!er way: using the contextmanager decorator
from contextlib import contextmanager
@contextmanager
def feature_flag(name, on=True):
""" The easier way to create Context Managers """
old_value = feature_flags.is_on(name)
feature_flags.toggle(name, on) # behavior of __enter__()
yield
feature_flags.toggle(name, old_value) # behavior of __exit__()
See: contextlib.contextmanager
Note: yield?
from contextlib import contextmanager
@contextmanager
def feature_flag(name, on=True):
""" The easier way to create Context Managers """
old_value = feature_flags.is_on(name)
feature_flags.toggle(name, on) # behavior of __enter__()
yield
feature_flags.toggle(name, old_value) # behavior of __exit__()
See: contextlib.contextmanager
either implementation
def get_homepage_url():
""" Method that returns the path of the home page we want to display. """
if feature_flags.is_on(FeatureFlags.SHOW_BETA):
return '/beta'
else:
return '/homepage'
def test_homepage_url_with_context_manager():
with feature_flag(FeatureFlags.SHOW_BETA):
# saw the beta homepage...
assert get_homepage_url() == '/beta'
with feature_flag(FeatureFlags.SHOW_BETA, on=False):
# saw the standard homepage...
assert get_homepage_url() == '/homepage'
@nnja
either implementation
def get_homepage_url():
""" Method that returns the path of the home page we want to display. """
if feature_flags.is_on(FeatureFlags.SHOW_BETA):
return '/beta'
else:
return '/homepage'
def test_homepage_url_with_context_manager():
with feature_flag(FeatureFlags.SHOW_BETA):
assert get_homepage_url() == '/beta'
print('seeing the beta homepage...')
with feature_flag(FeatureFlags.SHOW_BETA, on=False):
assert get_homepage_url() == '/homepage'
print('seeing the standard homepage...')
@nnja
Decorators
The simple explanation:
Syntactic sugar that allows modification of an underlying
function.
@nnja
Recap!
Decorators:
— Wrap a function in another function.
— Do something:
— before the call
— after the call
— with provided arguments
— modify the return value or arguments
@nnja
def say_after(hello_function):
def say_nice_to_meet_you(name):
hello_function(name)
print('It was nice to meet you!')
return say_nice_to_meet_you
def hello(name):
print('Hello', name)
>>> hello('Nina')
Hello Nina
>>> say_after(hello)('Nina')
Hello Nina It was nice to meet you!
— say_after(hello) returns the function
say_nice_to_meet_you
— then we call say_nice_to_meet_you('Nina')
@nnja
def say_after(hello_function):
def say_nice_to_meet_you(name):
hello_function(name)
print('It was nice to meet you!')
return say_nice_to_meet_you
@say_after
def hello(name):
print('Hello', name)
>>> hello('Nina')
Hello Nina It was nice to meet you!
— calling the decorated function hello(name)
— is the same as calling an undecorated hello with
say_after(hello)('Nina')
@nnja
closure example
def multiply_by(num):
def do_multiplication(x):
return x * num
return do_multiplication
multiply_by_five = multiply_by(5)
>>> multiply_by_five(4)
20
@nnja
decorators that take arguments
def greeting(argument):
def greeting_decorator(greet_function):
def greet(name):
greet_function(name)
print('It was %s to meet you!' % argument)
return greet
return greeting_decorator
@greeting('bad')
def aloha(name):
print ('Aloha', name)
@nnja
decorators that take arguments
def say_this_after(argument):
def say_after(hello_function):
def say_after_meeting(name):
hello_function(name)
print('It was %s to meet you' % argument)
return say_after_meeting
return say_after
@say_this_after('bad')
def hello(name):
print('Hello', name)
Is the same as calling this on an undecorated function:
say_after_bad = say_this_after('bad')(hello)
say_after_bad('Nina')
@nnja
losing context with a decorator
def say_bye(func):
def wrapper(name):
func()
print('Bye', name)
return wrapper
@say_bye
def my_name():
""" Say my name"""
print('Nina')
>>> my_name.__name__
'wrapper'
>>>> my_name.__doc__
# ... empty
@nnja
solution: use wraps, or wrapt library!
from contextlib import wraps
def say_adios(func):
@wraps(func) # pass in which function to wrap
def wrapper():
func()
print('Adios!')
return wrapper
@say_adios
def say_max():
""" Says the name Max"""
print('Max')
>>> say_max.__name__
'say_max'
>>> say_max.__doc__
' Says the name Max'
@nnja
Decorators: Common uses
— logging
— timing
— validation
— rate limiting
— mocking/patching
@nnja
ContextDecorators
ContextManagers
+ Decorators combined.
@nnja
As of python 3.2 ContextDecorators are in the standard
library. They're the best of both worlds!
— By using ContextDecorator you can easily write classes
that can be used both as decorators with @ and
context managers with the with statement.
— ContextDecorator is used by contextmanager(), so you
get this functionality
✨
automatically .
— Alternatively, you can write a class that extends from ContextDecorator or uses
ContextDecorator as a mixin, and implements __enter__, __exit__ and __call__
— If you use python2, a backport package is available here: contextlib2
@nnja
Remember @contextmanager from earlier?
from contextlib import contextmanager
@contextmanager
def feature_flag(name, on=True):
old_value = feature_flags.is_on(name)
feature_flags.toggle(name, on)
yield
feature_flags.toggle(name, old_value)
@nnja
use it as a context manager
def get_homepage_url():
beta_flag_on = feature_flags.is_on(FeatureFlags.SHOW_BETA)
return '/beta' if beta_flag_on else '/homepage'
with feature_flag(FeatureFlags.SHOW_BETA):
assert get_homepage_url() == '/beta'
or use as a decorator
@feature_flag(FeatureFlags.SHOW_BETA, on=False)
def get_profile_page():
beta_flag_on = feature_flags.is_on(FeatureFlags.SHOW_BETA)
return 'beta.html' if beta_flag_on else 'profile.html'
assert get_profile_page() == 'profile.html'
@nnja
library I
!
: freezegun lets your python tests ❇ travel
through time! ❇
from freezegun import freeze_time
# use it as a Context Manager
def test():
with freeze_time("2012-01-14"):
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
assert datetime.datetime.now() != datetime.datetime(2012, 1, 14)
# or a decorator
@freeze_time("2012-01-14")
def test():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
read the source sometime, it's mind-bending!
@nnja
NamedTuple
Useful when you need lightweight representations of
data.
Create tuple subclasses with named fields.
@nnja
Example
from collections import namedtuple
CacheInfo = namedtuple(
"CacheInfo", ["hits", "misses", "max_size", "curr_size"])
@nnja
Giving NamedTuples default values
RoutingRule = namedtuple(
'RoutingRule',
['prefix', 'queue_name', 'wait_time']
)
(1) By specifying defaults
RoutingRule.__new__.__defaults__ = (None, None, 20)
(2) or with _replace to customize a prototype instance
default_rule = RoutingRule(None, None, 20)
user_rule = default_rule._replace(prefix='user', queue_name='user-queue')
@nnja
NamedTuples can be subclassed and extended
class Person(namedtuple('Person', ['first_name', 'last_name'])):
""" Stores first and last name of a Person"""
__slots__ = ()
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
>>> me = Person('nina', 'zakharenko')
>>> str(me)
'nina zakharenko'
>>> me
Person(first_name='nina', last_name='zakharenko')
@nnja
Tip
Use __slots__ = () in your NamedTuples!
— It prevents the creation of instance dictionaries.
— It lowers memory consumption.
— Allows for faster access
@nnja
"Perfection is achieved, not when
there is nothing more to add, but
when there is nothing left to take
away."
— Antoine de Saint-Exupery
@nnja
New Tools
— Magic Methods
— make your objects behave like builtins (numbers,
list, dict, etc)
— Method ❇Magic❇
— alias methods
— * getattr
— functool.partial
@nnja
— ContextManagers
— Close resources
— Decorators
— do something before/after call, modify return value
or validate arguments
— ContextDecorators
— ContextManagers + Decorators combined!
@nnja
— Iterators & Generators
— Loop over your objects
— yield
— NamedTuple
— Lightweight classes
@nnja
Don't be
a mindless
Code
Monkey
@nnja
Use these
tools to be
an elegant
Pythonista!
@nnja
Thanks!
@nnja
nina@nnja.io
bit.ly/elegant-python-ca
@nnja

Weitere ähnliche Inhalte

Was ist angesagt?

Letswift Swift 3.0
Letswift Swift 3.0Letswift Swift 3.0
Letswift Swift 3.0Sehyun Park
 
JavaScript in 2016
JavaScript in 2016JavaScript in 2016
JavaScript in 2016Codemotion
 
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
 
eXo SEA - JavaScript Introduction Training
eXo SEA - JavaScript Introduction TrainingeXo SEA - JavaScript Introduction Training
eXo SEA - JavaScript Introduction TrainingHoat Le
 
Beyond the Style Guides
Beyond the Style GuidesBeyond the Style Guides
Beyond the Style GuidesMosky Liu
 
Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Dhaval Dalal
 
7 Stages of Unit Testing in iOS
7 Stages of Unit Testing in iOS7 Stages of Unit Testing in iOS
7 Stages of Unit Testing in iOSJorge Ortiz
 
Javascript Basics
Javascript BasicsJavascript Basics
Javascript Basicsmsemenistyi
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8Dhaval Dalal
 
React Native Evening
React Native EveningReact Native Evening
React Native EveningTroy Miles
 
Origins of Elixir programming language
Origins of Elixir programming languageOrigins of Elixir programming language
Origins of Elixir programming languagePivorak MeetUp
 
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
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingCodemotion
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterHaehnchen
 
Creating Lazy stream in CSharp
Creating Lazy stream in CSharpCreating Lazy stream in CSharp
Creating Lazy stream in CSharpDhaval Dalal
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)Javier Eguiluz
 
Swift Bengaluru Meetup slides
Swift Bengaluru Meetup slidesSwift Bengaluru Meetup slides
Swift Bengaluru Meetup slidesPushkar Kulkarni
 

Was ist angesagt? (20)

SWIFT 3
SWIFT 3SWIFT 3
SWIFT 3
 
Letswift Swift 3.0
Letswift Swift 3.0Letswift Swift 3.0
Letswift Swift 3.0
 
JavaScript in 2016
JavaScript in 2016JavaScript in 2016
JavaScript in 2016
 
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?
 
eXo SEA - JavaScript Introduction Training
eXo SEA - JavaScript Introduction TrainingeXo SEA - JavaScript Introduction Training
eXo SEA - JavaScript Introduction Training
 
Elixir
ElixirElixir
Elixir
 
Beyond the Style Guides
Beyond the Style GuidesBeyond the Style Guides
Beyond the Style Guides
 
Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)
 
7 Stages of Unit Testing in iOS
7 Stages of Unit Testing in iOS7 Stages of Unit Testing in iOS
7 Stages of Unit Testing in iOS
 
Javascript Basics
Javascript BasicsJavascript Basics
Javascript Basics
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8
 
React Native Evening
React Native EveningReact Native Evening
React Native Evening
 
Origins of Elixir programming language
Origins of Elixir programming languageOrigins of Elixir programming language
Origins of Elixir programming language
 
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?"
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
 
Creating Lazy stream in CSharp
Creating Lazy stream in CSharpCreating Lazy stream in CSharp
Creating Lazy stream in CSharp
 
Ad java prac sol set
Ad java prac sol setAd java prac sol set
Ad java prac sol set
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
 
Swift Bengaluru Meetup slides
Swift Bengaluru Meetup slidesSwift Bengaluru Meetup slides
Swift Bengaluru Meetup slides
 

Ähnlich wie Elegant Solutions For Everyday Python Problems - PyCon Canada 2017

1183 c-interview-questions-and-answers
1183 c-interview-questions-and-answers1183 c-interview-questions-and-answers
1183 c-interview-questions-and-answersAkash Gawali
 
Generators & Decorators.pptx
Generators & Decorators.pptxGenerators & Decorators.pptx
Generators & Decorators.pptxIrfanShaik98
 
An Overview Of Python With Functional Programming
An Overview Of Python With Functional ProgrammingAn Overview Of Python With Functional Programming
An Overview Of Python With Functional ProgrammingAdam Getchell
 
What's New In Python 2.4
What's New In Python 2.4What's New In Python 2.4
What's New In Python 2.4Richard Jones
 
Functions2.pdf
Functions2.pdfFunctions2.pdf
Functions2.pdfDaddy84
 
Functions_21_22.pdf
Functions_21_22.pdfFunctions_21_22.pdf
Functions_21_22.pdfpaijitk
 
C++ Interview Question And Answer
C++ Interview Question And AnswerC++ Interview Question And Answer
C++ Interview Question And AnswerJagan Mohan Bishoyi
 
C++ questions And Answer
C++ questions And AnswerC++ questions And Answer
C++ questions And Answerlavparmar007
 
Iterarators and generators in python
Iterarators and generators in pythonIterarators and generators in python
Iterarators and generators in pythonSarfaraz Ghanta
 
Introduction to python programming 2
Introduction to python programming   2Introduction to python programming   2
Introduction to python programming 2Giovanni Della Lunga
 
Functions_19_20.pdf
Functions_19_20.pdfFunctions_19_20.pdf
Functions_19_20.pdfpaijitk
 
Functions2.pdf
Functions2.pdfFunctions2.pdf
Functions2.pdfprasnt1
 
Porque aprender haskell me fez um programador python melhor?
Porque aprender haskell me fez um programador python melhor?Porque aprender haskell me fez um programador python melhor?
Porque aprender haskell me fez um programador python melhor?UFPA
 
Python Functions Tutorial | Working With Functions In Python | Python Trainin...
Python Functions Tutorial | Working With Functions In Python | Python Trainin...Python Functions Tutorial | Working With Functions In Python | Python Trainin...
Python Functions Tutorial | Working With Functions In Python | Python Trainin...Edureka!
 
Pemrograman Python untuk Pemula
Pemrograman Python untuk PemulaPemrograman Python untuk Pemula
Pemrograman Python untuk PemulaOon Arfiandwi
 
Python na Infraestrutura 
MySQL do Facebook

Python na Infraestrutura 
MySQL do Facebook
Python na Infraestrutura 
MySQL do Facebook

Python na Infraestrutura 
MySQL do Facebook
Artur Rodrigues
 

Ähnlich wie Elegant Solutions For Everyday Python Problems - PyCon Canada 2017 (20)

Functions2.pptx
Functions2.pptxFunctions2.pptx
Functions2.pptx
 
Advance python
Advance pythonAdvance python
Advance python
 
1183 c-interview-questions-and-answers
1183 c-interview-questions-and-answers1183 c-interview-questions-and-answers
1183 c-interview-questions-and-answers
 
Generators & Decorators.pptx
Generators & Decorators.pptxGenerators & Decorators.pptx
Generators & Decorators.pptx
 
An Overview Of Python With Functional Programming
An Overview Of Python With Functional ProgrammingAn Overview Of Python With Functional Programming
An Overview Of Python With Functional Programming
 
What's New In Python 2.4
What's New In Python 2.4What's New In Python 2.4
What's New In Python 2.4
 
Functions2.pdf
Functions2.pdfFunctions2.pdf
Functions2.pdf
 
Functions_21_22.pdf
Functions_21_22.pdfFunctions_21_22.pdf
Functions_21_22.pdf
 
C++ Interview Question And Answer
C++ Interview Question And AnswerC++ Interview Question And Answer
C++ Interview Question And Answer
 
C++ questions And Answer
C++ questions And AnswerC++ questions And Answer
C++ questions And Answer
 
Iterarators and generators in python
Iterarators and generators in pythonIterarators and generators in python
Iterarators and generators in python
 
Introduction to python programming 2
Introduction to python programming   2Introduction to python programming   2
Introduction to python programming 2
 
Functions.pdf
Functions.pdfFunctions.pdf
Functions.pdf
 
Functionscs12 ppt.pdf
Functionscs12 ppt.pdfFunctionscs12 ppt.pdf
Functionscs12 ppt.pdf
 
Functions_19_20.pdf
Functions_19_20.pdfFunctions_19_20.pdf
Functions_19_20.pdf
 
Functions2.pdf
Functions2.pdfFunctions2.pdf
Functions2.pdf
 
Porque aprender haskell me fez um programador python melhor?
Porque aprender haskell me fez um programador python melhor?Porque aprender haskell me fez um programador python melhor?
Porque aprender haskell me fez um programador python melhor?
 
Python Functions Tutorial | Working With Functions In Python | Python Trainin...
Python Functions Tutorial | Working With Functions In Python | Python Trainin...Python Functions Tutorial | Working With Functions In Python | Python Trainin...
Python Functions Tutorial | Working With Functions In Python | Python Trainin...
 
Pemrograman Python untuk Pemula
Pemrograman Python untuk PemulaPemrograman Python untuk Pemula
Pemrograman Python untuk Pemula
 
Python na Infraestrutura 
MySQL do Facebook

Python na Infraestrutura 
MySQL do Facebook
Python na Infraestrutura 
MySQL do Facebook

Python na Infraestrutura 
MySQL do Facebook

 

Mehr von Nina Zakharenko

Recovering From Git Mistakes - Nina Zakharenko
Recovering From Git Mistakes - Nina ZakharenkoRecovering From Git Mistakes - Nina Zakharenko
Recovering From Git Mistakes - Nina ZakharenkoNina Zakharenko
 
Code Review Skills for Pythonistas - Nina Zakharenko - EuroPython
Code Review Skills for Pythonistas - Nina Zakharenko - EuroPythonCode Review Skills for Pythonistas - Nina Zakharenko - EuroPython
Code Review Skills for Pythonistas - Nina Zakharenko - EuroPythonNina Zakharenko
 
How to successfully grow a code review culture
How to successfully grow a code review cultureHow to successfully grow a code review culture
How to successfully grow a code review cultureNina Zakharenko
 
Memory Management In Python The Basics
Memory Management In Python The BasicsMemory Management In Python The Basics
Memory Management In Python The BasicsNina Zakharenko
 
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 Minutes
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 MinutesDjangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 Minutes
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 MinutesNina Zakharenko
 
Nina Zakharenko - Introduction to Git - Start SLC 2015
Nina Zakharenko - Introduction to Git - Start SLC 2015Nina Zakharenko - Introduction to Git - Start SLC 2015
Nina Zakharenko - Introduction to Git - Start SLC 2015Nina Zakharenko
 
Djangocon 2014 angular + django
Djangocon 2014 angular + djangoDjangocon 2014 angular + django
Djangocon 2014 angular + djangoNina Zakharenko
 

Mehr von Nina Zakharenko (7)

Recovering From Git Mistakes - Nina Zakharenko
Recovering From Git Mistakes - Nina ZakharenkoRecovering From Git Mistakes - Nina Zakharenko
Recovering From Git Mistakes - Nina Zakharenko
 
Code Review Skills for Pythonistas - Nina Zakharenko - EuroPython
Code Review Skills for Pythonistas - Nina Zakharenko - EuroPythonCode Review Skills for Pythonistas - Nina Zakharenko - EuroPython
Code Review Skills for Pythonistas - Nina Zakharenko - EuroPython
 
How to successfully grow a code review culture
How to successfully grow a code review cultureHow to successfully grow a code review culture
How to successfully grow a code review culture
 
Memory Management In Python The Basics
Memory Management In Python The BasicsMemory Management In Python The Basics
Memory Management In Python The Basics
 
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 Minutes
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 MinutesDjangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 Minutes
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 Minutes
 
Nina Zakharenko - Introduction to Git - Start SLC 2015
Nina Zakharenko - Introduction to Git - Start SLC 2015Nina Zakharenko - Introduction to Git - Start SLC 2015
Nina Zakharenko - Introduction to Git - Start SLC 2015
 
Djangocon 2014 angular + django
Djangocon 2014 angular + djangoDjangocon 2014 angular + django
Djangocon 2014 angular + django
 

Kürzlich hochgeladen

GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identityteam-WIBU
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfDrew Moseley
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalLionel Briand
 
How To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROHow To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROmotivationalword821
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...confluent
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Hr365.us smith
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Salesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZSalesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZABSYZ Inc
 

Kürzlich hochgeladen (20)

Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identity
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdf
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive Goal
 
How To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROHow To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTRO
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Salesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZSalesforce Implementation Services PPT By ABSYZ
Salesforce Implementation Services PPT By ABSYZ
 

Elegant Solutions For Everyday Python Problems - PyCon Canada 2017

  • 1. Elegant Solutions For Everyday Python Problems Nina Zakharenko @nnja bit.ly/elegant-python-ca ℹ There are links in these slides. Follow along ^
  • 2. This talk is for you if: — You're an intermediate python programmer — You're coming to python from another language — You want to learn about fancy features like: magic methods, iterators, decorators, and context managers slides: bit.ly/elegant-python-ca @nnja
  • 4. How do we make code elegant? We pick the right tool for the job! Resources for converting from Python 2 -> 3
  • 5. Beauty is in the eye of the beholder
  • 7. You're used to implementing __str__ and __repr__ --but there's a whole other world of powerful magic methods! By implementing a few straightforward methods, you can make your objects behave like built-ins such as: — numbers — lists — dictionaries — and more... @nnja
  • 8. class Money: currency_rates = { '$': 1, '€': 0.88, } def __init__(self, symbol, amount): self.symbol = symbol self.amount = amount def __repr__(self): return '%s%.2f' % (self.symbol, self.amount) @nnja
  • 9. class Money: currency_rates = { '$': 1, '€': 0.88, } def __init__(self, symbol, amount): self.symbol = symbol self.amount = amount def __repr__(self): return '%s%.2f' % (self.symbol, self.amount) @nnja
  • 10. class Money: # defined currency_rates, __init__, and repr above... def convert(self, other): """Convert other amount to our currency""" new_amount = ( other.amount / self.currency_rates[other.symbol] * self.currency_rates[self.symbol]) return Money(self.symbol, new_amount) @nnja
  • 11. __repr__ in action >>> soda_cost = Money('$', 5.25) >>> soda_cost $5.25 >>> pizza_cost = Money('€', 7.99) >>> pizza_cost €7.99 @nnja
  • 12. class Money: def __add__(self, other): """ Add 2 Money instances using '+' """ new_amount = self.amount + self.convert(other).amount return Money(self.symbol, new_amount) @nnja
  • 13. >>> soda_cost = Money('$', 5.25) >>> pizza_cost = Money('€', 7.99) >>> soda_cost + pizza_cost $14.33 More on Magic Methods: Dive into Python3 - Special Method Names
  • 14. >>> soda_cost = Money('$', 5.25) >>> pizza_cost = Money('€', 7.99) >>> soda_cost + pizza_cost $14.33 >>> pizza_cost + soda_cost €12.61 More on Magic Methods: Dive into Python3 - Special Method Names @nnja
  • 15. some magic methods map to built-in functions class Alphabet: letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' def __len__(self): return len(self.letters) >>> my_alphabet = Alphabet() >>> len(my_alphabet) 26 @nnja
  • 17. Making classes iterable — In order to be iterable, a class needs to implement __iter__() — __iter__() must return an iterator — In order to be an iterator a class needs to implement __next__() which must raise StopIteration when there are no more items to return or next() in python2 ^ can be confusing at first, but remember these guidelines for making classesGreat explanation of iterable vs. iterator vs. generator
  • 18. class IterableServer: services = [ {'active': False, 'protocol': 'ftp', 'port': 21}, {'active': True, 'protocol': 'ssh', 'port': 22}, {'active': True, 'protocol': 'http', 'port': 21}, ] def __init__(self): self.current_pos = 0 def __iter__(self): # can return self, because __next__ implemented return self def __next__(self): while self.current_pos < len(self.services): service = self.services[self.current_pos] self.current_pos += 1 if service['active']: return service['protocol'], service['port'] raise StopIteration next = __next__ # optional python2 compatibility @nnja
  • 19. >>> for protocol, port in IterableServer(): print('service %s is running on port %d' % (protocol, port)) service ssh is running on port 22 service http is running on port 21 ... not bad @nnja
  • 20. tip: use a generator when your iterator doesn't need to maintain a lot of state @nnja
  • 21. class Server: services = [ {'active': False, 'protocol': 'ftp', 'port': 21}, {'active': True, 'protocol': 'ssh', 'port': 22}, {'active': True, 'protocol': 'http', 'port': 21}, ] def __iter__(self): for service in self.services: if service['active']: yield service['protocol'], service['port'] @nnja
  • 22. class Server: services = [ {'active': False, 'protocol': 'ftp', 'port': 21}, {'active': True, 'protocol': 'ssh', 'port': 22}, {'active': True, 'protocol': 'http', 'port': 21}, ] def __iter__(self): for service in self.services: if service['active']: yield service['protocol'], service['port'] @nnja
  • 23. Why does this work? use single parenthesis ( ) to create a generator comprehension ^ technically, a generator expression but I like this term better, and so does Ned Batchelder >>> my_gen = (num for num in range(1)) >>> my_gen <generator object <genexpr> at 0x107581bf8> @nnja
  • 24. An iterator must implement __next__() >>> next(my_gen) # remember __len__() mapped to built-in len() 0 and raise StopIteration when there are no more elements >>> next(my_gen) ... StopIteration Traceback (most recent call last) For more tools for working with iterators, check out itertools
  • 26. alias methods class Word: def __init__(self, word): self.word = word def __repr__(self): return self.word def __add__(self, other_word): return Word('%s %s' % (self.word, other_word)) # Add an alias from method __add__ to the method concat concat = __add__ @nnja
  • 27. When we add an alias from __add__ to concat because methods are just objects >>> # remember, concat = __add__ >>> first_name = Word('Max') >>> last_name = Word('Smith') >>> first_name + last_name Max Smith >>> first_name.concat(last_name) Max Smith >>> Word.__add__ == Word.concat True @nnja
  • 28. Dog class >>> class Dog: sound = 'Bark' def speak(self): print(self.sound + '!', self.sound + '!') >>> my_dog = Dog() >>> my_dog.speak() Bark! Bark! read the docs
  • 29. getattr(object, name, default) >>> class Dog: sound = 'Bark' def speak(self): print(self.sound + '!', self.sound + '!') >>> my_dog = Dog() >>> my_dog.speak() Bark! Bark! >>> getattr(my_dog, 'speak') <bound method Dog.speak of <__main__.Dog object at 0x10b145f28>> >>> speak_method = getattr(my_dog, 'speak') >>> speak_method() Bark! Bark! read the docs
  • 30. getattr(object, name, default) >>> class Dog: sound = 'Bark' def speak(self): print(self.sound + '!', self.sound + '!') >>> my_dog = Dog() >>> my_dog.speak() Bark! Bark! >>> getattr(my_dog, 'speak') <bound method Dog.speak of <__main__.Dog object at 0x10b145f28>> >>> speak_method = getattr(my_dog, 'speak') >>> speak_method() Bark! Bark! read the docs
  • 31. Example: command line tool with dynamic commands class Operations: def say_hi(self, name): print('Hello,', name) def say_bye(self, name): print ('Goodbye,', name) def default(self, arg): print ('This operation is not supported.') if __name__ == '__main__': operations = Operations() # let's assume error handling command, argument = input('> ').split() getattr(operations, command, operations.default)(argument) read the docs
  • 32. Output $ python getattr.py > say_hi Nina Hello, Nina > blah blah This operation is not supported. ✨ additional reading - inverse of getattr() is setattr()
  • 33. functool.partial(func, *args, **kwargs) — Return a new partial object which behaves like func called with args & kwargs — if more args are passed in, they are appended to args — if more keyword arguments are passed in, they extend and override kwargs read the docs on partials
  • 34. functool.partial(func, *args, **kwargs) >>> from functools import partial >>> basetwo = partial(int, base=2) >>> basetwo functools.partial(<class 'int'>, base=2) >>> basetwo('10010') 18 read the docs on partials
  • 35. library I ! : github.com/jpaugh/agithub agithub is a (badly named) REST API client with transparent syntax which facilitates rapid prototyping — on any REST API! — Implemented in 400 lines. — Add support for any REST API in ~30 lines of code. — agithub knows everything it needs to about protocol (REST, HTTP, TCP), but assumes nothing about your upstream API. @nnja
  • 36. define endpoint url & other connection properties class GitHub(API): def __init__(self, token=None, *args, **kwargs): props = ConnectionProperties( api_url = kwargs.pop('api_url', 'api.github.com')) self.setClient(Client(*args, **kwargs)) self.setConnectionProperties(props) then, start using the API! >>> gh = GitHub('token') >>> status, data = gh.user.repos.get(visibility='public', sort='created') >>> # ^ Maps to GET /user/repos >>> data ... ['tweeter', 'snipey', '...'] github.com/jpaugh/agithub
  • 38. class API: def __getattr__(self, key): return IncompleteRequest(self.client).__getattr__(key) __getitem__ = __getattr__ class IncompleteRequest: def __getattr__(self, key): if key in self.client.http_methods: htmlMethod = getattr(self.client, key) return partial(htmlMethod, url=self.url) else: self.url += '/' + str(key) return self __getitem__ = __getattr__ class Client: http_methods = ('get') # ... def get(self, url, headers={}, **params): return self.request('GET', url, None, headers) github.com/jpaugh/agithub source: base.py
  • 39. class API: def __getattr__(self, key): return IncompleteRequest(self.client).__getattr__(key) __getitem__ = __getattr__ class IncompleteRequest: def __getattr__(self, key): if key in self.client.http_methods: htmlMethod = getattr(self.client, key) return partial(htmlMethod, url=self.url) else: self.url += '/' + str(key) return self __getitem__ = __getattr__ class Client: http_methods = ('get') # ... def get(self, url, headers={}, **params): return self.request('GET', url, None, headers) github.com/jpaugh/agithub source: base.py
  • 40. class API: def __getattr__(self, key): return IncompleteRequest(self.client).__getattr__(key) __getitem__ = __getattr__ class IncompleteRequest: def __getattr__(self, key): if key in self.client.http_methods: htmlMethod = getattr(self.client, key) return partial(htmlMethod, url=self.url) else: self.url += '/' + str(key) return self __getitem__ = __getattr__ class Client: http_methods = ('get') # ... def get(self, url, headers={}, **params): return self.request('GET', url, None, headers) github.com/jpaugh/agithub source: base.py
  • 41. given a non-existant path: >>> status, data = this.path.doesnt.exist.get() >>> status ... 404 & because __getitem__ is aliased to __getattr__: >>> owner, repo = 'nnja', 'tweeter' >>> status, data = gh.repos[owner][repo].pulls.get() >>> # ^ Maps to GET /repos/nnja/tweeter/pulls >>> data .... # {....} github.com/jpaugh/agithub
  • 42. Context Managers & new in python 3: async context managers
  • 43. When should I use one? Need to perform an action before and/or after an operation. Common scenarios: — Closing a resource after you're done with it (file, network connection) — Perform cleanup before/after a function call @nnja
  • 44. Example Problem: Feature Flags Turn features of your application on and off easily. Uses of feature flags: — A/B Testing — Rolling Releases — Show Beta version to users opted-in to Beta Testing Program More on Feature Flags
  • 45. Example - FeatureFlags Class class FeatureFlags: """ Example class which stores Feature Flags and their state. """ SHOW_BETA = 'Show Beta version of Home Page' flags = { SHOW_BETA: True } @classmethod def is_on(cls, name): return cls.flags[name] @classmethod def toggle(cls, name, on): cls.flags[name] = on feature_flags = FeatureFlags() @nnja
  • 46. How do we temporarily turn features on and off when testing flags? Want: with feature_flag(FeatureFlags.SHOW_BETA): assert '/beta' == get_homepage_url() @nnja
  • 47. Using Magic Methods __enter__ and __exit__ class feature_flag: """ Implementing a Context Manager using Magic Methods """ def __init__(self, name, on=True): self.name = name self.on = on self.old_value = feature_flags.is_on(name) def __enter__(self): feature_flags.toggle(self.name, self.on) def __exit__(self, *args): feature_flags.toggle(self.name, self.old_value) See: contextlib.contextmanager
  • 48. The be!er way: using the contextmanager decorator from contextlib import contextmanager @contextmanager def feature_flag(name, on=True): old_value = feature_flags.is_on(name) feature_flags.toggle(name, on) yield feature_flags.toggle(name, old_value) See: contextlib.contextmanager
  • 49. The be!er way: using the contextmanager decorator from contextlib import contextmanager @contextmanager def feature_flag(name, on=True): """ The easier way to create Context Managers """ old_value = feature_flags.is_on(name) feature_flags.toggle(name, on) # behavior of __enter__() yield feature_flags.toggle(name, old_value) # behavior of __exit__() See: contextlib.contextmanager
  • 50. Note: yield? from contextlib import contextmanager @contextmanager def feature_flag(name, on=True): """ The easier way to create Context Managers """ old_value = feature_flags.is_on(name) feature_flags.toggle(name, on) # behavior of __enter__() yield feature_flags.toggle(name, old_value) # behavior of __exit__() See: contextlib.contextmanager
  • 51. either implementation def get_homepage_url(): """ Method that returns the path of the home page we want to display. """ if feature_flags.is_on(FeatureFlags.SHOW_BETA): return '/beta' else: return '/homepage' def test_homepage_url_with_context_manager(): with feature_flag(FeatureFlags.SHOW_BETA): # saw the beta homepage... assert get_homepage_url() == '/beta' with feature_flag(FeatureFlags.SHOW_BETA, on=False): # saw the standard homepage... assert get_homepage_url() == '/homepage' @nnja
  • 52. either implementation def get_homepage_url(): """ Method that returns the path of the home page we want to display. """ if feature_flags.is_on(FeatureFlags.SHOW_BETA): return '/beta' else: return '/homepage' def test_homepage_url_with_context_manager(): with feature_flag(FeatureFlags.SHOW_BETA): assert get_homepage_url() == '/beta' print('seeing the beta homepage...') with feature_flag(FeatureFlags.SHOW_BETA, on=False): assert get_homepage_url() == '/homepage' print('seeing the standard homepage...') @nnja
  • 53. Decorators The simple explanation: Syntactic sugar that allows modification of an underlying function. @nnja
  • 54. Recap! Decorators: — Wrap a function in another function. — Do something: — before the call — after the call — with provided arguments — modify the return value or arguments @nnja
  • 55. def say_after(hello_function): def say_nice_to_meet_you(name): hello_function(name) print('It was nice to meet you!') return say_nice_to_meet_you def hello(name): print('Hello', name) >>> hello('Nina') Hello Nina >>> say_after(hello)('Nina') Hello Nina It was nice to meet you! — say_after(hello) returns the function say_nice_to_meet_you — then we call say_nice_to_meet_you('Nina') @nnja
  • 56. def say_after(hello_function): def say_nice_to_meet_you(name): hello_function(name) print('It was nice to meet you!') return say_nice_to_meet_you @say_after def hello(name): print('Hello', name) >>> hello('Nina') Hello Nina It was nice to meet you! — calling the decorated function hello(name) — is the same as calling an undecorated hello with say_after(hello)('Nina') @nnja
  • 57. closure example def multiply_by(num): def do_multiplication(x): return x * num return do_multiplication multiply_by_five = multiply_by(5) >>> multiply_by_five(4) 20 @nnja
  • 58. decorators that take arguments def greeting(argument): def greeting_decorator(greet_function): def greet(name): greet_function(name) print('It was %s to meet you!' % argument) return greet return greeting_decorator @greeting('bad') def aloha(name): print ('Aloha', name) @nnja
  • 59. decorators that take arguments def say_this_after(argument): def say_after(hello_function): def say_after_meeting(name): hello_function(name) print('It was %s to meet you' % argument) return say_after_meeting return say_after @say_this_after('bad') def hello(name): print('Hello', name) Is the same as calling this on an undecorated function: say_after_bad = say_this_after('bad')(hello) say_after_bad('Nina') @nnja
  • 60. losing context with a decorator def say_bye(func): def wrapper(name): func() print('Bye', name) return wrapper @say_bye def my_name(): """ Say my name""" print('Nina') >>> my_name.__name__ 'wrapper' >>>> my_name.__doc__ # ... empty @nnja
  • 61. solution: use wraps, or wrapt library! from contextlib import wraps def say_adios(func): @wraps(func) # pass in which function to wrap def wrapper(): func() print('Adios!') return wrapper @say_adios def say_max(): """ Says the name Max""" print('Max') >>> say_max.__name__ 'say_max' >>> say_max.__doc__ ' Says the name Max' @nnja
  • 62. Decorators: Common uses — logging — timing — validation — rate limiting — mocking/patching @nnja
  • 64. As of python 3.2 ContextDecorators are in the standard library. They're the best of both worlds! — By using ContextDecorator you can easily write classes that can be used both as decorators with @ and context managers with the with statement. — ContextDecorator is used by contextmanager(), so you get this functionality ✨ automatically . — Alternatively, you can write a class that extends from ContextDecorator or uses ContextDecorator as a mixin, and implements __enter__, __exit__ and __call__ — If you use python2, a backport package is available here: contextlib2 @nnja
  • 65. Remember @contextmanager from earlier? from contextlib import contextmanager @contextmanager def feature_flag(name, on=True): old_value = feature_flags.is_on(name) feature_flags.toggle(name, on) yield feature_flags.toggle(name, old_value) @nnja
  • 66. use it as a context manager def get_homepage_url(): beta_flag_on = feature_flags.is_on(FeatureFlags.SHOW_BETA) return '/beta' if beta_flag_on else '/homepage' with feature_flag(FeatureFlags.SHOW_BETA): assert get_homepage_url() == '/beta' or use as a decorator @feature_flag(FeatureFlags.SHOW_BETA, on=False) def get_profile_page(): beta_flag_on = feature_flags.is_on(FeatureFlags.SHOW_BETA) return 'beta.html' if beta_flag_on else 'profile.html' assert get_profile_page() == 'profile.html' @nnja
  • 67. library I ! : freezegun lets your python tests ❇ travel through time! ❇ from freezegun import freeze_time # use it as a Context Manager def test(): with freeze_time("2012-01-14"): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) assert datetime.datetime.now() != datetime.datetime(2012, 1, 14) # or a decorator @freeze_time("2012-01-14") def test(): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) read the source sometime, it's mind-bending! @nnja
  • 68. NamedTuple Useful when you need lightweight representations of data. Create tuple subclasses with named fields. @nnja
  • 69. Example from collections import namedtuple CacheInfo = namedtuple( "CacheInfo", ["hits", "misses", "max_size", "curr_size"]) @nnja
  • 70. Giving NamedTuples default values RoutingRule = namedtuple( 'RoutingRule', ['prefix', 'queue_name', 'wait_time'] ) (1) By specifying defaults RoutingRule.__new__.__defaults__ = (None, None, 20) (2) or with _replace to customize a prototype instance default_rule = RoutingRule(None, None, 20) user_rule = default_rule._replace(prefix='user', queue_name='user-queue') @nnja
  • 71. NamedTuples can be subclassed and extended class Person(namedtuple('Person', ['first_name', 'last_name'])): """ Stores first and last name of a Person""" __slots__ = () def __str__(self): return '%s %s' % (self.first_name, self.last_name) >>> me = Person('nina', 'zakharenko') >>> str(me) 'nina zakharenko' >>> me Person(first_name='nina', last_name='zakharenko') @nnja
  • 72. Tip Use __slots__ = () in your NamedTuples! — It prevents the creation of instance dictionaries. — It lowers memory consumption. — Allows for faster access @nnja
  • 73. "Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away." — Antoine de Saint-Exupery @nnja
  • 74. New Tools — Magic Methods — make your objects behave like builtins (numbers, list, dict, etc) — Method ❇Magic❇ — alias methods — * getattr — functool.partial @nnja
  • 75. — ContextManagers — Close resources — Decorators — do something before/after call, modify return value or validate arguments — ContextDecorators — ContextManagers + Decorators combined! @nnja
  • 76. — Iterators & Generators — Loop over your objects — yield — NamedTuple — Lightweight classes @nnja
  • 78. Use these tools to be an elegant Pythonista! @nnja