+ All Categories
Home > Technology > An Extreme Talk about the Zen of Python

An Extreme Talk about the Zen of Python

Date post: 09-May-2015
Category:
Upload: daniel-greenfeld
View: 1,476 times
Download: 2 times
Share this document with a friend
Description:
In the Python community we are taught from the outset of learning the language that the Zen of Python serves as a guide for how we should construct our codebases and projects. Rather than go into the zen-like meanings of each statement, this talk will explore how individual koans are implemented via detailed displays of sophisticated code examples.
101
Daniel Greenfeld pydanny.com / @pydanny An Extreme Talk about the Zen of Python Daniel Greenfeld PyCon Poland 2012
Transcript
Page 1: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

An Extreme Talk about the Zen of Python

Daniel Greenfeld

PyCon Poland2012

Page 2: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

• Mother’s family were from Poland circa 1903.

Dynow, Poland

@pydanny

• Daniel Greenfeld

• Father’s parents were from Poland circa 1920.

Dynow, Polandto USA

Page 3: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

• Principal at Cartwheel Web

• Member of Python Software Foundation

• Member of Django Software Foundation

@pydanny

• Learned Python at NASA

Page 4: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

@pydanny

Audrey Roy (Fiancée)

Page 5: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

• pydanny.com

• pydanny-event-notes.rtfd.org

• djangopackages.com

• pyramid.opencomparison.com

@pydanny

• http://bit.ly/pyconpl-notes

Page 6: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Intro

Page 7: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

The Zen of Python>>> import thisThe Zen of Python, by Tim Peters

Beautiful is better than ugly.Explicit is better than implicit.Simple is better than complex.Complex is better than complicated.Flat is better than nested.Sparse is better than dense.Readability counts.Special cases aren't special enough to break the rules.Although practicality beats purity.Errors should never pass silently.Unless explicitly silenced.In the face of ambiguity, refuse the temptation to guess.There should be one-- and preferably only one --obvious way to do it.Although that way may not be obvious at first unless you're Dutch.Now is better than never.Although never is often better than *right* now.If the implementation is hard to explain, it's a bad idea.If the implementation is easy to explain, it may be a good idea.Namespaces are one honking great idea -- let's do more of those!

Page 8: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Tim Peters

https://en.wikipedia.org/wiki/Timsort

Timsort is a hybrid sorting algorithm, derived from merge sort and insertion sort, designed to perform well on many kinds of real-world data. It was invented by Tim Peters in 2002 for use in the Python programming language. The algorithm finds subsets of the data that are already ordered, and uses the subsets to sort the data more efficiently. This is done by merging an identified subset, called a run, with existing runs until certain criteria are fulfilled. Timsort has been Python's standard sorting algorithm since version 2.3. It is now also used to sort arrays in Java SE 7, and on the Android platform.

Author of Timsort

Page 9: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Let’s get startedPart I

Page 10: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

The OpeningBeautiful is better than ugly.Explicit is better than implicit.Simple is better than complex.Complex is better than complicated.Flat is better than nested.Sparse is better than dense.Readability counts.

Page 11: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

super()

Page 12: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

import mathclass Circle(object):

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

def area(self): return self.radius ** 2 *math.pi

def __repr__(self): return '{0} as area {1}'.format( self.__class__.__name__, self.area() )

class Ring(Circle):

def __init__(self, outer, inner): super(Ring, self).__init__(outer) self.inner = inner

def area(self): outer, inner = self.radius, self.inner return Circle(outer).area() - Circle(inner).area()

Circle>> Circle(10)Circle as area 314.159265359

>>> Ring(10, 5)235.619449019

The super method calls the parent class, which is Circle

What if our inheritanceisn’t simple?

Page 13: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Contention

The super() method can create ambiguity.

Page 14: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

The OpeningBeautiful is better than ugly.Explicit is better than implicit.Simple is better than complex.Complex is better than complicated.Flat is better than nested.Sparse is better than dense.Readability counts.

If the implementation is hard to explain, it's a bad idea.If the implementation is easy to explain, it may be a good idea.

Page 15: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

The OpeningBeautiful is better than ugly.Explicit is better than implicit.Simple is better than complex.Complex is better than complicated.Flat is better than nested.Sparse is better than dense.Readability counts.

If the implementation is hard to explain, it's a bad idea.If the implementation is easy to explain, it may be a good idea.

Ambiguity of super() method

Who actually remembers the super() syntax?

In the face of ambiguity, refuse the temptation to guess.Ambiguity of

super() method

Page 16: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

import mathclass Circle(object):

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

def area(self): return self.radius ** 2 *math.pi

def __repr__(self): return '{0} as area {1}'.format( self.__class__.__name__, self.area() )

class Ring2(Circle):

def __init__(self, outer, inner): Circle.__init__(self, outer) self.inner = inner

def area(self): outer, inner = self.radius, self.inner return Circle(outer).area() - Circle(inner).area()

Circle II>> Circle(10)Circle as area 314.159265359

>>> Ring2(10, 5)235.619449019

Absolutely inheriting __init__ from Circle

Explicit

Simpler

More readable

Note: Only do this when you need it.

Page 17: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Explicit > Implicit

Circle.__init__(self, outer) super(Ring, self).__init__(outer)>

Page 18: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Another example.

Page 19: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Django class based views

• Composition

• Inheritance

• Subclass

• Polymorphism

• Lots of other big words

Page 20: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

However...

Page 21: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Quiz

What is the ancestor chain for django.views.generic.edit.UpdateView?

Page 22: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Answer

django.views.generic.edit.UpdateViewdjango.views.generic.detail.SingleObjectTemplateResponseMixindjango.views.generic.base.TemplateResponseMixindjango.views.generic.edit.BaseUpdateViewdjango.views.generic.edit.ModelFormMixindjango.views.generic.edit.FormMixindjango.views.generic.detail.SingleObjectMixindjango.views.generic.edit.ProcessFormViewdjango.views.generic.base.View

The ancestor chain for django.views.generic.edit.UpdateView:

Page 23: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Beautiful is better than ugly.Explicit is better than implicit.Simple is better than complex.Complex is better than complicated.Flat is better than nested.Sparse is better than dense.Readability counts.

The Opening

If the implementation is hard to explain, it's a bad idea.If the implementation is easy to explain, it may be a good idea.

In the face of ambiguity, refuse the temptation to guess.

Ambiguity of super method

Ambiguity of super method

Who actually remembers the super() syntax?

Page 24: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Answer

django.views.generic.edit.UpdateViewdjango.views.generic.detail.SingleObjectTemplateResponseMixindjango.views.generic.base.TemplateResponseMixindjango.views.generic.edit.BaseUpdateViewdjango.views.generic.edit.ModelFormMixindjango.views.generic.edit.FormMixindjango.views.generic.detail.SingleObjectMixindjango.views.generic.edit.ProcessFormViewdjango.views.generic.base.View

The ancestor chain for django.views.generic.edit.UpdateView:

Page 25: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

def form_valid(self, form): verb_form = verb_form_base(self.request.POST) if verb_form.is_valid(): form.instance.verb_attributes = verb_form.cleaned_data return super(ActionUpdateView, self).form_valid(form)

A form_valid() implementation

Which form_valid() am I calling?

Page 26: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

class ActionUpdateView( LoginRequiredMixin, # django-braces ActionBaseView, # inherits from AuthorizedForProtocolMixin AuthorizedforProtocolEditMixin, # Checks rights on edit views VerbBaseView, # Gets one of 200+ verb forms UpdateView): # django.views.generic.BaseView

def form_valid(self, form): verb_form = verb_form_base(self.request.POST) if verb_form.is_valid(): form.instance.verb_attributes = verb_form.cleaned_data return super(ActionUpdateView, self).form_valid(form)

A form_valid() implementationOMG!

OMG!

OMG!

Page 27: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

from actions.views import ActionUpdateViewfor x in ActionUpdateView.mro(): print(x)

Ancestor Chain (MRO) of ActionUpdateView

MRO = Method Resolution Order

Print the MRO

Page 28: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Ancestor Chain (MRO) of ActionUpdateView

<class 'actions.views.ActionUpdateView'><class 'braces.views.LoginRequiredMixin'><class 'actions.views.ActionBaseView'><class 'core.views.AuthorizedForProtocolMixin'><class 'core.views.AuthorizedforProtocolEditMixin'><class 'verbs.views.VerbBaseView'><class 'django.views.generic.edit.UpdateView'><class 'django.views.generic.detail.SingleObjectTemplateResponseMixin'><class 'django.views.generic.base.TemplateResponseMixin'><class 'django.views.generic.edit.BaseUpdateView'><class 'django.views.generic.edit.ModelFormMixin'><class 'django.views.generic.edit.FormMixin'><class 'django.views.generic.detail.SingleObjectMixin'><class 'django.views.generic.edit.ProcessFormView'><class 'django.views.generic.base.View'><type 'object'>

Page 29: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

from actions.views import ActionUpdateViewfor x in [x for x in ActionUpdateView.mro() if hasattr(x, "form_valid")]: print(x)

Ancestor Chain (MRO) of ActionUpdateView

Filter the MRO list to only include classes with a form_valid() nethod

Page 30: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Ancestor Chain (MRO) of ActionUpdateView

<class 'actions.views.ActionUpdateView'><class 'django.views.generic.edit.UpdateView'><class 'django.views.generic.edit.BaseUpdateView'><class 'django.views.generic.edit.ModelFormMixin'><class 'django.views.generic.edit.FormMixin'>

super’s chosenform_valid() ancestor

Current class

Page 31: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Whew!

Page 32: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Safe!

Page 33: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

If you’re not careful, super can cause subtle

inheritance/MRO problems.

Page 34: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

In the face of ambiguity, refuse the temptation to guess.

The Opening

If the implementation is hard to explain, it's a bad idea.If the implementation is easy to explain, it may be a good idea.

Ambiguity of super method

Possibly theseas well

Ambiguity of super method

Beautiful is better than ugly.Explicit is better than implicit.Simple is better than complex.Complex is better than complicated.Flat is better than nested.Sparse is better than dense.Readability counts.

Who actually remembers the super() syntax?

Page 35: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

• Hope that anyone else maintaining this project isn’t going to kill me.

• Convert to a functional view.

• Explore better patterns.

Possible mitigations for this view.

• return UpdateView.form_valid(self, form)

Page 36: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Moving on...Part II

Page 37: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Controversy

Special cases aren’t special enough to break the rules.Although practicality beats purity.

Page 38: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Controversy: Django

• WSGI (fixed)

• Configuration and installation (working on it)

• Class Based Views (We’re working on it)

• Not Model-View-Controller compliant

Page 39: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Django: Not MVC

• Django follows Model-Template-View.

• Is the web appropriate for MVC?

• The Zen of Python doesn’t mention MVC.

• But it’s all moot because...

...what we really care about is...

Page 40: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Separation of presentation from content.

Django does a good job.

Page 41: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Well... maybe not CBVs...

Django is pretty good about following the Zen of Python

Controversy

Special cases aren’t special enough to break the rules.Although practicality beats purity.

Page 42: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Controversy: Web2py

• Often honors Implicit over Explicit

• Follows its own namespace pattern

Page 43: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Web2py code sample# encoding: utf-8# https://github.com/mdipierro/evote/blob/master/models/menu.py# this file is released under public domain and # you can use without limitations

response.title = 'Voting Service'response.subtitle = None

## read more at http://dev.w3.org/html5/markup/meta.name.htmlresponse.meta.author = 'Your Name <[email protected]>'response.meta.description = 'a cool new app'response.meta.keywords = 'web2py, python, framework'response.meta.generator = 'Web2py Web Framework'

# snip more content that I cut in the name of brevity

Response object magically exists.No import necessary

What can I expect in any location?What about namespace pollution?

Page 44: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Contention

• Explicit is better than implicit

• In the name of ambiguity, refuse the temptation to guess

• Namespaces are one honking great idea -- let's do more of those!

Web2py violates these 3 koans:

Page 45: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Controversy

Special cases aren’t special enough to break the rules.Although practicality beats purity.

Page 46: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Special cases aren’t special enough to break the rules.Although practicality beats purity.

Web2py contends:

Page 47: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Web2py contends:

• Implicit behaviors means Web2py is easier for beginners to learn.

• The Web2py namespace pattern is easy to learn.

• For experienced developers, commonly repeated imports are boilerplate.

Note: This is my interpretation of Web2py design considerations.

Personal side note: Web2py is very easy to install.

Page 48: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Just like Django.

Web2py will always be contentious

Web2py argues practicalityin some very specific places.

Controversy

Special cases aren’t special enough to break the rules.Although practicality beats purity.

Well... maybe not CBVs...

Django is pretty good about following the Zen of Python

Page 49: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Fixing Exceptions to Exception handling

Part III

Page 50: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Exceptions

Errors should never pass silently.Unless explicitly silenced.

Page 51: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Django Packages

• Once a day iterates across all packages.

• Updates the metadata from:

• Github:

• Bitbucket

• PyPI

Page 52: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Django Packages

• Sometimes the APIs go down.

• Sometimes the APIs change.

• Sometimes projects get deleted.

• Sometimes the Internets fail

Problems

Catch and report exceptions!

Page 53: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

package_updater.py...for package in Package.objects.all(): try: package.fetch_metadata() package.fetch_commits() except socket_error, e: text += "\nFor '%s', threw a socket_error: %s" % \

(package.title, e) continue # snip lots of other exceptions except Exception, e: text += "\nFor '%s', General Exception: %s" % \

(package.title, e) continue

# email later

https://github.com/opencomparison/opencomparison/blob/master/package/management/commands/package_updater.py

http://bit.ly/Q8v9xk

Um...

Page 54: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

What I’m doing now

>>> try:... a = b... except Exception as e:... print(e)...name 'b' is not defined

What’s the error type?!?

Where is my stack trace?!?

(and it’s wrong)

Page 55: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

What I want

>>> a = bTraceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name 'b' is not defined

Traceback

Error typeError message

Page 56: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Exceptions

Errors should never pass silently.Unless explicitly silenced.

My code is nearly silent

I’ve silenced things for no good reason

Page 57: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Getting what I want>>> class CustomErrorHandler(Exception):... def __init__(self, error):... print(error)... print(type(error))...>>> try:... a=b... except Exception as e:... raise CustomErrorHandler(e)...name 'b' is not definedTraceback (most recent call last): File "<stdin>", line 4, in <module>__main__.CustomErrorHandlerNameError

Traceback

Error message

For this exampleprint == log

No color because it’s a print statement

Error Type

Page 58: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

PackageUpdaterException

Nice message

Full traceback

All errors caught

class PackageUpdaterException(Exception): def __init__(self, error, title): log_message = "For {title}, {error_type}: {error}".format( title=title, error_type=type(error), error=error ) logging.error(log_message) logging.exception(error)

for package in Package.objects.all(): try: try: package.fetch_metadata() package.fetch_commits() except Exception, e: raise PackageUpdaterException(e, package.title) except PackageUpdaterException: continue

Loop forward

Page 59: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Exceptions

Errors should never pass silently.Unless explicitly silenced.

My code is nearly silent

I’ve silenced things for no good reason

Page 60: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Cleaner codePart IV

Page 61: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

More controversy

In the face of ambiguity, refuse the temptation to guess.There should be one-- and preferably only one --obvious way to do it.Although that way may not be obvious at first unless you're Dutch.

Page 62: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

You try to shoot yourself in the foot, only to realize there’s no need, since Guido

thoughtfully shot you in the foot years ago.

-- Nick Mathewson, comp.lang.python

http://starship.python.net/~mwh/quotes.html

More controversy

Page 63: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Decorators

@memoizedef allcaps(string): return string.upper()

def allcaps(string): return string.upper()

allcaps = memoize(allcaps)>

Decorators are easy to explain!

Page 64: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Decorator Template

http://pydanny-event-notes.readthedocs.org/en/latest/SCALE10x/python-decorators.html#decorator-template

def decorator(function_to_decorate): def wrapper(*args, **kwargs): # do something before invoation result = func_to_decorate(*args, **kwargs)

# do something after return result # update wrapper.__doc__ and .func_name # or functools.wraps return wrapper

Result is returned when the wrapper is done

When decorated function iscalled decorator returns wrapper

Wrapper function does things before

and after the function is called here.

Wrapper function does things before

and after the function is called here.

Page 65: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Decorator implementation

def memoize(func): cache = {}

def memoized(*args): if args in cache: return cache[args] result = cache[args] = func(*args) return result

return memoized

@memoizedef allcaps(string): return string.upper()

Return function

Return value

set cache

Return value if args in cache

Datastore

Page 66: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Whew.

Page 67: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

What about decorators that accept arguments?

Page 68: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Oh no.

Page 69: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Explaining this is hard.

Page 70: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

multiplier decorator

def multiplier(multiple): def decorator(function): def wrapper(*args, **kwargs): return function(*args, **kwargs) * multiple return wrapper return decorator

@multiplier(5)def allcaps(string): return string.upper()

Multiplier function sets the state for the multiple

argument

When decorated function is called the decorator function returns the wrapper function

Result is returned when the wrapper is done.

Wrapper function does:

What am I supposed to highlight?

Page 71: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Whew.

Page 72: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Oh no.

Page 73: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Not done yet!

Page 74: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

authentication decorator

import functoolsdef authorization(roles): def decorator(function): @functools.wraps(function) def wrapper(*args, **kwargs): check_roles(user, roles) return function(*args, **kwargs) return wrapper return decorator

@authorization('admin')def do_admin_thing(user): # do something administrative return user

Don’t forget functools!

Page 75: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Whew.

Page 76: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Really.

Page 77: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

It is not easy to explain how

to write decorators.

Page 78: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Contention

Writing decorators is not.

Using decorators is like Zen.

Page 79: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

More controversy

In the face of ambiguity, refuse the temptation to guess.There should be one-- and preferably only one --obvious way to do it.Although that way may not be obvious at first unless you're Dutch.

If the implementation is hard to explain, it's a bad idea.If the implementation is easy to explain, it may be a good idea.

Although practicality beats purity.

Decorators are easy to explain!

Decorators are hard to explain!

Page 80: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

The last sectionPart IV

Page 81: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Getting it done vs.

Technical debtNow is better than never.Although never is often better than *right* now.If the implementation is hard to explain, it's a bad idea.If the implementation is easy to explain, it may be a good idea.Namespaces are one honking great idea -- let's do more of those!

Page 82: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Getting it done vs.

Technical debtNow is better than never.Although never is often better than *right* now.

Namespaces are one honking great idea -- let's do more of those!

Page 83: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Getting it done vs.

Technical debt

Now is better than never.Although never is often better than *right* now.Namespaces are one honking great idea -- let's do more of those!

Page 84: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

• Tests

• Documentation

Some things take time

Page 85: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

• Tests

• Documentation

Some things take time

Risk: Deploying broken code

Risk: problems upgrading dependencies

Risk: Forgetting install/deploy

Risk: Multiple coding standards

(You can skip them)

Page 86: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Must-have Documentation

• Installation/Deployment procedures

• Coding standards

• How to run tests

• Version (including __version__)

Page 87: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Easy Test Patterns

• Always make sure your test harness can run

• Try using tests instead of the shell/repl.

• After the first deadline, reject any incoming code that drops coverage.

• Use coverage.py

For developers racing to meet deadlines:

Page 88: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Getting technical again...

Page 89: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Namespaces

• Extremely powerful

• Useful

• Precise

import reimport os

from twisted.internet import protocol, reactor

from django import formsfrom myproject import utils

Page 90: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

import * makesdevelopment faster[1]

• Extremely powerful

• Useful

• Imports everything at once! [2]

from re import *from os import *from twisted import *from django.forms import *from myproject.utils import *

[1]Warning: import * can be dangerous

[2]Warning: import * can be dangerous

Page 91: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Comparing two modulesdef compare(mod1, mod2): title = '\nComparing {0}, {1}:'.format( mod1.__name__, mod2.__name__ ) print(title) for x in dir(mod1): for y in dir(mod2): if x == y and not x.startswith('_'): print("* " + x)

Page 92: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Comparing two modules

>>> re.sys == os.sysTrue

>>> re.error == os.errorFalse

>>> import re>>> import os

>>> compare(os, re)Comparing os, re:* sys* error

import * can get you into trouble

from re import *from os import *

Page 93: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Breaking built-ins

def compare_builtins(mod1): print("\nComparing {0} to builtins:".format(mod1.__name__)) for x in dir(mod1): for y in dir(globals()['__builtins__']): if x == y and not x.startswith('_'): print("* GLOBAL: {0}".format(x))

Checks to see if a module has itemsthat match any Python built-in.

Page 94: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Breaking built-ins

>>> compare_builtins(re)Comparing re to builtins:* GLOBAL: compile

>>> compare_builtins(os)Comparing os to builtins:* GLOBAL: open

from re import *from os import *

Breaks compile() built-in.

Annoying but infrequent problem.

Breaks open() built-in.

This can drive you crazy.

Page 95: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

The open() story

from os import *after

before

Breaks allthe

things!

Help on built-in function open in module __builtin__:

open(...) open(name[, mode[, buffering]]) -> file object

Open a file using the file() type, returns a file object. This is the preferred way to open a file. See file.__doc__ for further information.

Help on built-in function open in module posix:

open(...) open(filename, flag [, mode=0777]) -> fd

Open a file (for low level IO).

Page 96: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Contention

import * is not for beginners.

import * is people who really know Python.

__all__ = ["echo", "surround", "reverse"]

Page 97: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Summary

Page 98: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

The Zen of Python>>> import thisThe Zen of Python, by Tim Peters

Beautiful is better than ugly.Explicit is better than implicit.Simple is better than complex.Complex is better than complicated.Flat is better than nested.Sparse is better than dense.Readability counts.Special cases aren't special enough to break the rules.Although practicality beats purity.Errors should never pass silently.Unless explicitly silenced.In the face of ambiguity, refuse the temptation to guess.There should be one-- and preferably only one --obvious way to do it.Although that way may not be obvious at first unless you're Dutch.Now is better than never.Although never is often better than *right* now.If the implementation is hard to explain, it's a bad idea.If the implementation is easy to explain, it may be a good idea.Namespaces are one honking great idea -- let's do more of those!

Page 99: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Thank you

• Richard Jones

• Raymond Hettiger

• Matt Harrison

• Kenneth Love

• Audrey Roy

• PyCon Poland

• Filip Kłębczyk

• Piotr Kasprzyk

• Lennart Regebro

Page 100: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

One more thing...

Page 101: An Extreme Talk about the Zen of Python

Daniel Greenfeldpydanny.com / @pydanny

Q & A


Recommended