|
Size: 1328
Comment: converted to 1.6 markup
|
Size: 1881
Comment:
|
| Deletions are marked like this. | Additions are marked like this. |
| Line 13: | Line 13: |
| * '''[[http://www.interlink.com.au/anthony/tech/talks/OSCON2005/effective_r27.pdf|OSCON2005-effective_r27.pdf]]''' | '''[[http://www.interlink.com.au/anthony/tech/talks/OSCON2005/effective_r27.pdf|OSCON2005-effective_r27.pdf]]''' |
| Line 15: | Line 15: |
| * 新下载: http://www.slideshare.net/rawwell/effectiver27 * 同类体验: 1. [[http://www.avatar.se/python/Python_course.pdf|Learning Python~A course in programming ]]^2004 Per Kraulis^ 1. [[http://www.slideshare.net/laiyonghao/python-7905416|赖勇浩《python温故》]] 1. [[http://www.slideshare.net/doughellmann/hidden-treasures-of-the-python-standard-library|Hidden Treasures of the Python Standard Library]] * 翻译: [[http://blog.csdn.net/liuyuan_jq/archive/2011/03/30/6288478.aspx|大白熊的专栏 - CSDN博客]] 1. |
Effective--实效Python编程
Contents
1. Effective Py Pregramming
- 奇妙的令人激动不以的 Python 编程技法汇总!
- 同类体验:
[[http://www.avatar.se/python/Python_course.pdf|Learning Python~A course in programming
]]2004 Per Kraulis
1.1. 试译
Effective Python Programming – OSCON 2005
Effective Python Programming
Page 2
Effective Python Programming – OSCON 2005
Effective Programming
●
Get the job done
●
Better, more maintainable code
●
Use the language's strengths
●
Python is not:
C++
Java
Perl
...
Page 3
Effective Python Programming – OSCON 2005
Laziness
●
In development, laziness can be good
●
Do things right the first time
●
Don't re-invent every wheel
●
Death to NIH
Page 4
Effective Python Programming – OSCON 2005
Effective != Efficient
●
Effective does not necessarily mean
efficient
●
Optimise for development time
●
Then worry about performance
●
We'll touch on efficient code, later
Page 5
Effective Python Programming – OSCON 2005
Target
●
Python 2.4
●
CPython
Page 6
Effective Python Programming – OSCON 2005
Python Fundamentals
●
Learning by tinkering
●
Everything's an object
●
Namespaces
●
EAFP
●
Duck Typing
Page 7
Effective Python Programming – OSCON 2005
Short Attention Span Theatre
●
Key things to remember
●
Even if you sleep through the rest,
you'll still get something
Page 8
Effective Python Programming – OSCON 2005
S.A.S. Theatre
●
Rule #1: Dictionaries
●
Rule #2: See Rule #1
Page 9
Effective Python Programming – OSCON 2005
Programming with the hood up
●
Introspection
●
Experimentation
Page 10
Effective Python Programming – OSCON 2005
Interactive Python
bonanza% python
Python 2.4.1 (#2, Mar 30 2005, 21:51:10)
[GCC 3.3.5 (Debian 1:3.3.5-8ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" ...
>>>
Page 11
Effective Python Programming – OSCON 2005
help and dir
●
help(obj) – formats docstrings
●
dir(obj) – shows attributes
Page 12
Effective Python Programming – OSCON 2005
help
>>> import os
>>> help(os.popen)
Help on built-in function popen in module posix:
popen(...)
popen(command [, mode='r' [, bufsize]]) -> pipe
Open a pipe to/from a command returning a file
object.
Page 13
Effective Python Programming – OSCON 2005
help...
>>> help(8)
Help on int object:
class int(object)
| int(x[, base]) -> integer
|
| Convert a string or number to an integer, if
| possible. A floating point argument will be
| truncated towards zero (this does not include a
| string representation of a floating point
| number!) When converting a string, use
| the optional base. It is an error to supply a
Page 14
Effective Python Programming – OSCON 2005
dir
>>> import popen2
>>> dir(popen2)
['MAXFD', 'Popen3', 'Popen4', '__all__',
'__builtins__', '__doc__', '__file__', '__name__',
'_active', '_cleanup', '_test', 'os', 'popen2',
'popen3', 'popen4', 'sys']
Page 15
Effective Python Programming – OSCON 2005
Everything is an object
●
ints, strings, files
●
functions, modules, classes
●
Variables are just labels
Page 16
Effective Python Programming – OSCON 2005
Objects vs Names
●
Variables are references
●
Just a name referring to an object
●
Stored in a namespace
(defaults to the local namespace)
Page 17
Effective Python Programming – OSCON 2005
Namespaces...
●
Namespaces are dictionaries!
>>> import sys
>>> def foo(a=1, b=2):
... c = "hello"
... print sys._getframe().f_locals
...
>>>
>>> foo(a=4)
{'a': 4, 'c': 'hello', 'b': 2}
Page 18
Effective Python Programming – OSCON 2005
Namespace lookup – Classic
●
locals
●
module globals
●
built-ins
Page 19
Effective Python Programming – OSCON 2005
Assignment
●
Assignment goes to local namespace
●
Unless 'global' statement
Page 20
Effective Python Programming – OSCON 2005
global
●
global only for assignment
●
not needed for getting a value
●
globals are slower!
Page 21
Effective Python Programming – OSCON 2005
Namespaces – nested scopes
●
statically nested scopes
(nested function definitions)
●
useful for lambda:
def createUpdater(self):
return lambda foo, bar: self.update(foo,bar)
●
nested function calls
example later of this
Page 22
Effective Python Programming – OSCON 2005
EAFP
●
Easier to Ask Forgiveness than
Permission
●
Very basic Python concept
Page 23
Effective Python Programming – OSCON 2005
Permission...
●
Permission:
if hasattr(obj, 'value'):
value = obj.value
else:
value = None
●
Forgiveness:
try:
read = obj.value
except AttributeError:
value = None
Page 24
Effective Python Programming – OSCON 2005
EAFP
●
Exceptions are expensive
●
Checks can also be expensive
●
Case-by-case – how often is it expected
to fail?
Page 25
Effective Python Programming – OSCON 2005
Python Typing
●
Weak vs Strong
●
Static vs Dynamic
●
C++/Java: strong static typing
●
Python: strong dynamic typing
Page 26
Effective Python Programming – OSCON 2005
Duck-Typing
●
Walks like a duck
●
... quacks like a duck
●
... it's a duck
Page 27
Effective Python Programming – OSCON 2005
Duck-Typing
●
File-like objects
●
Might only need 'read()'
Page 28
Effective Python Programming – OSCON 2005
Duck-Typing – File objects
def getData(obj):
data = obj.read()
print data
f = open('file.txt')
getData(f)
●
Actually, that data file was gzipped:
import gzip
f = gzip.GzipFile('file.txt.gz')
getData(f)
Page 29
Effective Python Programming – OSCON 2005
More Duck-Typing
●
The mapping interface (dictionary)
●
Start with a dictionary
●
Slot in a different implementation
●
e.g. network, database, ...
Page 30
Effective Python Programming – OSCON 2005
Interfaces
●
zope.interface
●
PyProtocols
●
Assert that an object implements an
interface
●
Documentation
●
Adaptation
●
Future Python
Page 31
Effective Python Programming – OSCON 2005
Structured Programming
Page 32
Effective Python Programming – OSCON 2005
Control Flow
●
Iterators
●
Generators
●
for/else
●
try/finally
●
try/except/else
●
switch statement
Page 33
Effective Python Programming – OSCON 2005
S.A.S. Theatre!
●
enumerate
for n in range(len(sequence)):
element = sequence[n]
●
instead:
for n, element in enumerate(sequence):
●
enumerate returns an iterator
>>> print enumerate([])
<enumerate object at 0xb7df418c>
Page 34
Effective Python Programming – OSCON 2005
Basic control flow
●
while
●
for
●
try/except
Page 35
Effective Python Programming – OSCON 2005
Iterators
●
Returns the next item each time
●
No need to have all items in memory
●
More flexible
Page 36
Effective Python Programming – OSCON 2005
Files are iterators
●
Returns a line
>>> for line in open('/etc/resolv.conf'):
... print "got line '%s'"%(line.strip())
...
got line 'nameserver 210.15.254.240'
got line 'nameserver 210.15.254.241'
got line 'nameserver 203.10.110.101'
got line 'nameserver 203.17.103.1'
Page 37
Effective Python Programming – OSCON 2005
Creating iterators
●
iter() built-in
●
turns a sequence into an iterator
●
classes can have an __iter__ method
that returns an iterator
Page 38
Effective Python Programming – OSCON 2005
More flexible for loops
●
Call .next() to get the next item
iterobj = iter(sequence)
for item in iterobj:
if item == 'extended':
item = item + iterobj.next()
Page 39
Effective Python Programming – OSCON 2005
Token streams
tokens=['text:hello','style:bold','text:world',
'text:goodbye','style:italic','text:world']
tokens = iter(tokens)
for tok in tokens:
what,value = tok.split(':',1)
if what == 'text':
handlePlainToken(value)
elif what == 'style':
what, value = tok.next().split(':', 1)
if style == 'bold':
handleBoldToken(value)
elif style == 'italic':
handleItalicToken(value)
Page 40
Effective Python Programming – OSCON 2005
Push Iterator
●
Sometimes you want to check the next
item, but not always consume it
●
Push it back onto the iterator!
●
Like stdio's getc()/ungetc()
Page 41
Effective Python Programming – OSCON 2005
Push Iterator
class PushIterator:
def __init__(self, iter):
self.iter = iter
self.pushed = []
def push(self, value):
self.pushed.append(value)
def next(self):
if self.pushed:
return self.pushed.pop()
else:
return self.iter.next()
def __iter__(self):
return self
Page 42
Effective Python Programming – OSCON 2005
Peek Iterator
●
Sibling to PushIterator
●
Peek at the next result (without
consuming it)
Page 43
Effective Python Programming – OSCON 2005
itertools
●
high performance iterator manipulation
●
functional programming
Page 44
Effective Python Programming – OSCON 2005
Generators
●
“Good artists copy, great artists steal”
- Picasso
●
Stolen from Icon
●
functions containing 'yield' are a
generator
●
When called, returns a generator object
●
... which is an iterator
Page 45
Effective Python Programming – OSCON 2005
Generators
●
'yield' passes a result to the caller
●
execution is suspended
●
when next() is called again, resumes
where it left off
Page 46
Effective Python Programming – OSCON 2005
Generators
>>> def squares(start=1):
... while True:
... yield start * start
... start += 1
...
>>> sq = squares(4)
>>> sq
<generator object at 0xb7df440c>
>>> sq.next()
16
>>> sq.next()
25
Page 47
Effective Python Programming – OSCON 2005
Generators
●
finish when they fall off the end
●
or 'return'
●
Generators can't 'return' a value
●
Generators can be called multiple times
Page 48
Effective Python Programming – OSCON 2005
Multiple Generator Calls
>>> s1 = squares(5)
>>> s2 = squares(15)
>>> print s1.next(), s2.next(), s1.next(), s2.next()
25 225 36 256
Page 49
Effective Python Programming – OSCON 2005
Generator Example
●
DB-API
●
cursor.fetchone() - get one row
Inefficient!
●
cursor.fetchall() - get all rows
Could consume a lot of memory
●
cursor.fetchmany(N) – get N rows
Slightly fiddly
Page 50
Effective Python Programming – OSCON 2005
Possible Solutions
for row in cursor.fetchall():
processResult(row)
row = cursor.fetchone()
while row:
processResult(row)
row = cursor.fetchone()
while True:
rows = cursor.fetchmany(100)
if not rows:
break
for row in rows:
processResult(row)
Page 51
Effective Python Programming – OSCON 2005
Generator Version
def ResultIter(cursor, arraysize=1000):
while True:
results = cursor.fetchmany(arraysize)
if not results:
break
for result in results:
yield result
●
Using this:
for res in ResultIter(cursor):
processRow(res)
Page 52
Effective Python Programming – OSCON 2005
for/else
●
for statements can have an else: clause
●
executed when the for loop exhausts
it's loop (no 'break', return or
exception)
Page 53
Effective Python Programming – OSCON 2005
for/else example
for element in sequence:
if elementMatched(element):
correct = element
break
else:
print "no elements matched"
correct = None
Page 54
Effective Python Programming – OSCON 2005
try/finally
●
finally: clause is always executed
●
resource cleanup
lock = acquireLock()
try:
val = doSomeStuff()
if val is None:
raise ValueError('got None')
elif val < 0:
return
finally:
lock.release()
Page 55
Effective Python Programming – OSCON 2005
try/finally
●
Great for preventing those nightmare
bugs
●
“This should never happen”
●
Chances are it will
●
Program Defensively
The Universe Hates You.
●
Woefully underused
Page 56
Effective Python Programming – OSCON 2005
try/except/else
●
try/except can have an else: statement
●
executed when no exception occurred
Page 57
Effective Python Programming – OSCON 2005
try/except/else
●
Put only the important bits in the try:
block
try:
import gtk
except:
MyWindow = None
else:
MyWindow = gtk.Window()
Page 58
Effective Python Programming – OSCON 2005
minimising code in a try: block
●
This code has a problem:
try:
data = obj.read()
except AttributeError:
data = ''
●
This masks any AttributeErrors in the
read() method
●
Source of hard-to-find bugs
Page 59
Effective Python Programming – OSCON 2005
switch statement
●
python has no switch/case
●
if/elif/elif/elif/else
●
use a dictionary
Page 60
Effective Python Programming – OSCON 2005
Dispatch via dict
if indata == 'FOZZIE':
showFozzie()
elif indata == 'KERMIT':
showKermit()
...
else:
showUnknownMuppet()
●
becomes:
callDict = { 'FOZZIE': showFozzie,
'KERMIT': showKermit,
... }
func = callDict.get(indata, showUnknownMuppet)
func()
Page 61
Effective Python Programming – OSCON 2005
Object Oriented Programming
Page 62
Effective Python Programming – OSCON 2005
Using Classes Pythonically
●
New-style vs Old-style
●
More Ducks!
●
isinstance
●
inheritance, mixins
●
access control
●
Simplifying your APIs
Page 63
Effective Python Programming – OSCON 2005
S.A.S. Theatre
●
__del__ is not your friend
Page 64
Effective Python Programming – OSCON 2005
__del__ often considered harmful
●
C++/Java-ism
●
__del__ breaks garbage collector
●
non-deterministic
●
doesn't always get called usefully when
Python is exiting
●
use a weakref in some cases
Page 65
Effective Python Programming – OSCON 2005
New-style vs Old-style
●
Python has two types of class
●
Old-style classes are the original ones
●
New-style (in 2.2) fix issues with these
Difference between C types and Python
classes
Can inherit from built-in types (e.g. dict)
Some shiny new features
Page 66
Effective Python Programming – OSCON 2005
New-style vs Old-style
●
New style derive from 'object'
●
New style classes in 2.2
●
Fix for implementation issues in original
classes
●
Many new features
properties
descriptors
__new__
.....
Page 67
Effective Python Programming – OSCON 2005
Use New Style Classes
●
Most new code should use them
●
Will become the default in Python 3.0
Page 68
Effective Python Programming – OSCON 2005
More Ducks!
●
Objects supporting the mapping
interface:
dictionaries
*dbm database files
shelves
db_row instances
Page 69
Effective Python Programming – OSCON 2005
Sometimes you care
●
There are times when you care what
things are passed
●
Check for the methods you need
if hasattr(obj, 'read'):
obj.read()
else:
raise ValueError
●
Or use an Interface
Page 70
Effective Python Programming – OSCON 2005
Interfaces
●
Documentation
●
Assertions
def getAudioFromSource(obj):
if not IAudio(obj):
raise ValueError('expected audio, got %r'%
obj)
return audio.read()
●
Adaptation
Automatically adapt an IFoo to an IBar
Page 71
Effective Python Programming – OSCON 2005
Interface Example
class IAudio(Interface):
'''Lowlevel interface to audio source/sink.'''
def close():
'''Close the underlying audio device'''
def reopen():
'''Reopen a closed audio device'''
def isOpen():
'''Return True if underlying audio open'''
def read():
'''Return a packet of audio from device.'''
def write(data):
'''Write audio to device.'''
Page 72
Effective Python Programming – OSCON 2005
Using an Interface
class ALSAAudio(object):
implements(IAudio)
def reopen(self):
....
def close(self):
....
def isOpen(self):
....
alsa = ALSAAudio()
IAudio.implementedBy(alsa)
IAudio(alsa)
Page 73
Effective Python Programming – OSCON 2005
Interfaces are dynamic
●
Interfaces can be changed at runtime
●
Assert that a 3
rd
party object
implements an interface
●
Register an adapter from one Interface
to another
Page 74
Effective Python Programming – OSCON 2005
isinstance
●
Checking obj.__class__ is evil
●
Breaks subclassing
●
type(foo) is ancient, and clunky
●
Use isinstance:
if isinstance(num, basestring):
num = int(num)
if not isinstance(thing, (int, float)):
raise ValueError('expected a number')
Page 75
Effective Python Programming – OSCON 2005
inheritance, mixins
●
Multiple inheritance is useful
●
Mixin classes – assemble components
into a class
●
Select from multiple implementations
Page 76
Effective Python Programming – OSCON 2005
Inheritance
●
“Flat is better than nested”
●
Excessive inheritance trees are painful
●
Use inheritance when you need it
Page 77
Effective Python Programming – OSCON 2005
Design for subclassing
●
Use self.__class__ instead of hardcoded
class names
class Item:
def __init__(self, value):
self.value = value
def getNextItem(self):
newItem = self.__class__()
newItem.value = self.value + 1
Page 78
Effective Python Programming – OSCON 2005
Base class methods
●
Call base class methods from
subclassed methods!
●
Protects you if parent class changes
●
Particularly important for __init__
class Monkey(Simian):
def __init__(self, bananas=2, *args, **kwargs):
self.bananas = bananas
Simian.__init__(self, *args, **kwargs)
Page 79
Effective Python Programming – OSCON 2005
Don't Assume You Know Best
●
You don't know how people will need to
use your code
●
Think about how someone could extend
your classes
●
Design classes accordingly
●
Document the methods
●
Factor out the useful bits
Page 80
Effective Python Programming – OSCON 2005
access control
●
Another C++/Java-ism
friend, public, private, ...
●
Python: “Everyone's a consenting
adult”
●
Convention: leading underscore signals
“implementation detail”
●
Better yet: document the API of the
class
Page 81
Effective Python Programming – OSCON 2005
__private names
●
leading double underscore mangles
names
●
In theory useful to stop people stepping
on implementation details
●
In practice, annoying
Personal goal for 2.5 is to remove all use
from the stdlib
Page 82
Effective Python Programming – OSCON 2005
Simplifying your APIs
●
Damien Conway's “Sufficiently
Advanced Magic”
●
But not quite that advanced...
Page 83
Effective Python Programming – OSCON 2005
Container object
●
Get the objects in a container
●
First attempt:
for child in container.getChildren():
doSomethingWithObject(child)
●
Unnecessary API
●
Python already has a good way to spell
this:
for child in container:
doSomethingWithObject(child)
Page 84
Effective Python Programming – OSCON 2005
Container example
●
Using the iterator protocol
class Container(object):
def __init__(self, *children):
self.children = children
def __iter__(self):
return iter(self.children)
cont = Container(1,2,3,4,5)
for c in cont:
print c
Page 85
Effective Python Programming – OSCON 2005
__special__ methods
●
Used to implement operators
●
Examples:
__str__ - string representation
__setitem__ -
obj[key] = val ==> obj.__setitem__(key,val)
__add__ - add something to this object
__getattr__ - get an attribute of this object
__eq__ - object is being compared to another
Page 86
Effective Python Programming – OSCON 2005
special methods, examples
●
A + B
First tries A.__add__(B)
Then B.__radd__(A)
(We're ignoring __coerce__)
●
A == B
In order: A.__eq__(B), B.__eq__(A),
A.__cmp__(B), and then B.__cmp__(A)
Page 87
Effective Python Programming – OSCON 2005
Make the API Intuitive
●
Every new method name is something
that has to be
remembered
documented
●
Finite amount of brain space
●
Use intuitive operators
●
But don't get too clever
Page 88
Effective Python Programming – OSCON 2005
C++-style cout
●
A bit too magical to be recommended:
class CppFile:
def __init__(self, fp):
self.fp = fp
def __lshift__(self, someobj):
self.fp.write(str(someobj))
return self
import sys
cout = CppFile(sys.stdout)
cout << "hello” << “world\n"
Page 89
Effective Python Programming – OSCON 2005
Demonstrating special methods
class chatty:
def __init__(self, name):
self.name = name
def __getattr__(self, what):
print self.name, "asked for", what
raise AttributeError(what)
Page 90
Effective Python Programming – OSCON 2005
demonstration...
>>> A = chatty('A')
>>> B = chatty('B')
>>> A + B
A asked for __coerce__
A asked for __add__
B asked for __coerce__
B asked for __radd__
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unsupported operand type(s) for +:
'instance' and 'instance'
>>> print A
A asked for __str__
A asked for __repr__
<__main__.chatty instance at 0xb7df47cc>
Page 91
Effective Python Programming – OSCON 2005
__getattr__ warning
●
Special-case __special__ names
●
Pain, otherwise
●
Python uses lots of special methods
●
e.g. __repr__ to print
def __getattr__(self, name):
if name.startswith('__') and name.endswith('__'):
raise AttributeError(name)
return self.remoteObject.lookupName(name)
Page 92
Effective Python Programming – OSCON 2005
Get/Set methods
●
instead of:
print someobject.getValue()
someobject.setValue(5)
●
use:
print someobject.value
someobject.value = 5
Page 93
Effective Python Programming – OSCON 2005
Get/Set methods
●
Sometimes, attributes need to be
computed
●
Use a property!
class Magic:
def _getMagicNum(self):
return findTheMagicNumber()
def _setMagicNum(self, value)
setTheMagicNumber(value)
magicNumber = property(_getMagicNum,
_setMagicNum)
Page 94
Effective Python Programming – OSCON 2005
Properties
●
Property takes 1-4 arguments:
attribute = property(getmeth, setmeth, delmeth,
doc='')
●
set method and del method optional
●
doc sets a docstring – use it
monkeyCount = property(getMonkeys,
doc='The count of monkeys in this barrel')
●
Only use property when needed
Attributes are a lot faster
Page 95
Effective Python Programming – OSCON 2005
Descriptors
●
property returns an object called a
descriptor
●
extremely powerful, but you'll have to
read up on them yourself
●
descriptors are how 'self' gets inserted
as the first argument of a method
●
classmethod and staticmethod are also
descriptors
Page 96
Effective Python Programming – OSCON 2005
staticmethod
●
Very limited use
●
Nearly always better to use a function
Page 97
Effective Python Programming – OSCON 2005
classmethod
●
Alternate constructors
class TimeStamp(object):
def __init__(self, h, m, s):
self.h, self.m, self.s = h, m, s
@classmethod
def fromString(cls, string):
h,m,s = [int(x) for x in string.split(':')]
return cls(h, m, s)
●
Alternate constructors make nicer API
●
Not many other uses
Page 98
Effective Python Programming – OSCON 2005
@classmethod !?
●
Decorators
●
Replaces this:
def alternateCtor(cls, argumentList):
...
alternateCtor = classmethod(alternateCtor)
●
With this:
@classmethod
def alternateCtor(cls, argumentList):
...
Page 99
Effective Python Programming – OSCON 2005
Decorators
●
Decorators are passed the function
object, return a new function object
●
Remember to copy func_name and
__doc__ if you create a new function
object!
Page 100
Effective Python Programming – OSCON 2005
Laziness
●
Python makes things easy
●
But only if you let it
●
Anytime you feel like you're doing too
much, take a step back
Page 101
Effective Python Programming – OSCON 2005
S.A.S. Theatre
●
dict.setdefault(key, defaultval)
●
sets a value (if not already set), returns
value
Page 102
Effective Python Programming – OSCON 2005
setdefault
●
Turns this:
if key in dictobj:
dictobj[key].append(val)
else:
dictobj[key] = [val]
●
Into this:
dictobj.setdefault(key, []).append(val)
Page 103
Effective Python Programming – OSCON 2005
Sequence Unpacking
●
Most things Just Work:
a, b, c = threetuple
●
Swap two values:
a, b = b, a
●
Get and clear a value:
val, self.val = self.val, None
Page 104
Effective Python Programming – OSCON 2005
Stamping License Plates
●
Any time you find yourself writing the
same/similar code repeatedly, you're
working too hard
●
Use a template function (a closure)
Page 105
Effective Python Programming – OSCON 2005
Boring repetitive code
class Monkey:
def displayNameAsHTML(self):
cssClass = self.cssClass
html='<div class=”%s”>%s</div>'%(cssClass,
self.name)
return html
def displayBananasAsHTML(self):
cssClass = self.cssClass
html='<div class=”%s”>%s</div>'%(cssClass,
self.bananas)
return html
Page 106
Effective Python Programming – OSCON 2005
Templated Monkey
def _displayer(what):
def template(self):
val = getattr(self, what)
cssClass = self.cssClass
return '<div class=”%s”>%s</div>'%(cssClass,
val)
return html
return template
class Monkey:
displayNameAsHTML = _displayer('name')
displayBananasAsHTML = _displayer('bananas')
Page 107
Effective Python Programming – OSCON 2005
Making Templates saner
def _displayer(what):
def template(self, what=what):
...
template.func_name = 'display%sAsHtml'%(
what.capitalize())
template.__doc__ = 'Returns %s as HTML'%what
return template
Page 108
Effective Python Programming – OSCON 2005
Universal Newline Mode
●
Windows, Mac, Unix have different line
endings
●
Annoying
●
Open files with 'rU', and it just works
fp = open('somefile.txt', 'rU')
Page 109
Effective Python Programming – OSCON 2005
codecs.open
●
codecs.open provides a file-like object
in a particular encoding
●
useful for reading and writing
●
more duck typing
Page 110
Effective Python Programming – OSCON 2005
Plan for Unicode
●
Much easier if you start out allowing
unicode
●
Even if not, it's not too hard to retrofit
Page 111
Effective Python Programming – OSCON 2005
basestring
●
Parent class for str and unicode
●
Useful in isinstance() checks
>>> isinstance('moose', basestring)
True
>>> isinstance(u'møøse', basestring)
True
Page 112
Effective Python Programming – OSCON 2005
The Instant Guide to i18n
●
i18n your strings:
from gettext import gettext as _
_('Enter your name')
●
Decode strings on input:
bytes = "naïve"
unistr = bytes.decode('iso8859-1')
●
Encode unicode on output:
print unistr.encode('iso8859-1', 'replace')
Page 113
Effective Python Programming – OSCON 2005
Batteries Included
●
Python ships with a large std library
●
Don't re-invent the wheel
Page 114
Effective Python Programming – OSCON 2005
When Things Go Pear-Shaped
●
Debugging
●
Testing
Page 115
Effective Python Programming – OSCON 2005
S.A.S. Theatre
●
The single most useful Python trick I
know:
import pdb; pdb.set_trace()
●
When executed, drops into the Python
debugger
Page 116
Effective Python Programming – OSCON 2005
unittest
●
Python standard unittest module
●
Port of Junit
●
Makes writing tests not-too-horrible
●
API is still a bit cumbersome
Page 117
Effective Python Programming – OSCON 2005
doctest
●
More Pythonic
●
Perfect for the lazy programmer
●
Cut-n-paste from an interactive session
●
Doubles as documentation and
examples
Page 118
Effective Python Programming – OSCON 2005
Running Tests
●
A good test runner makes it more likely
people will actually run the tests
●
test.py (in Zope3)
Page 119
Effective Python Programming – OSCON 2005
Dealing with tracebacks
●
Sometimes, the default traceback isn't
what you want
●
traceback module
try:
....
except:
e, v, tb = sys.exc_info()
traceback.print_tb(t)
Page 120
Effective Python Programming – OSCON 2005
cgitb
●
Debugging CGI scripts can be horrible
import cgitb; cgitb.enable()
●
Displays nicely formatted tracebacks
context
variables
arguments
●
Can log in text or html, to the browser
or files
Page 121
Effective Python Programming – OSCON 2005
Making Life Hard For Yourself
●
Things to avoid
●
Recognising refactoring targets
●
Learning from (bad) examples
Page 122
Effective Python Programming – OSCON 2005
S.A.S. Theatre
●
Bare except: clauses will nearly always
bite you later
●
Silently eating exceptions is bad
●
except: should either log the exception,
or re-raise it
●
Just 'raise' will re-raise the current
exception
Page 123
Effective Python Programming – OSCON 2005
Consistent Coding Style
●
Pick a style, and stick to it
PEP 008 has one, or choose your own
●
Use tools where necessary
emacs python mode
reindent.py
●
Pick a consistent indent style!
Page 124
Effective Python Programming – OSCON 2005
from module import *
●
Don't
●
Figuring out where a name comes from
should not be painful
Page 125
Effective Python Programming – OSCON 2005
Circular Imports
●
Circular imports lead to subtle bugs:
●
Module A:
import moduleB
●
Module B:
import moduleA
●
Defer imports until you need them to
fix this
Page 126
Effective Python Programming – OSCON 2005
more on exceptions
●
Raising a new exception from an
except: clause often makes debugging
harder
●
The new traceback will point at the
except: block, not the original
exception
●
A bare 'raise' will re-raise the current
exception
Page 127
Effective Python Programming – OSCON 2005
Refactoring Targets
●
Learn to spot potential problems
Page 128
Effective Python Programming – OSCON 2005
Long Argument Lists
●
Once a function gets past a couple of
arguments, either:
refactor it
or use keyword arguments
def someHideousFunction(firstname, surname, addr1,
addr2, zipcode, city, state):
....
someHideousFunction(firstname=”Anthony”,
surname=”Baxter”, ....
Page 129
Effective Python Programming – OSCON 2005
Format Strings
●
Similar problem with format strings
using % operator
●
Use the dict form:
addrInfo = dict(firstname='Anthony',
surname='Baxter', ...)
label = “””%(firstname)s %(surname)s
%(addr1)s
%(addr2)s
%(city)s, %(state)s
%(zipcode)s””” % addrInfo
Page 130
Effective Python Programming – OSCON 2005
string.Template
●
Even simpler
>>> from string import Template
>>> s = Template('$cheese is from ${country}')
>>> print s.substitute(cheese='Gouda', country='the
Netherlands')
Gouda is from the Netherlands
>>> print s.substitute(cheese='Gouda')
Traceback (most recent call last):
[...]
KeyError: 'country'
>>> print s.safe_substitute(cheese='Gouda')
Gouda is from ${country}
Page 131
Effective Python Programming – OSCON 2005
$ == Perl!?!
●
The $ sign is only accepted in the
strings passed to string.Template
●
Lots of other languages use $ - it's the
obvious choice
Page 132
Effective Python Programming – OSCON 2005
key in sequence
●
Any time you use 'in', check the RHS
●
If a sequence, how big will it get?
●
O(N)
●
Use a dict, or a set
Page 133
Effective Python Programming – OSCON 2005
Too many globals
●
Overuse of 'global' usually indicates
poor code
●
Refactor into a class, storing the global
values as attributes
Page 134
Effective Python Programming – OSCON 2005
Learning by (bad) example
●
Lots of Python code to learn from
●
Some of it is old
●
People pick up bad habits from this
Page 135
Effective Python Programming – OSCON 2005
map/filter/reduce
●
map and filter using a lambda should
be replaced with listcomps or genexprs
●
reduce: just don't use
sum() replaced 90% of use cases
other use cases usually leads to
headscratching
Page 136
Effective Python Programming – OSCON 2005
string module
●
string methods are better
>>> import string
>>> name = 'anthony'
>>> print string.upper(name)
ANTHONY
>>> print name.upper()
ANTHONY
●
Remember: strings are immutable,
methods return a copy
Page 137
Effective Python Programming – OSCON 2005
backslash line continuations
●
Almost never needed
●
Not needed if there's open braces
●
So wrap in ( )
●
Works for import, too! (in 2.4)
from package.subpkg.module import (Aname, Bname,
Cname, Dname)
Page 138
Effective Python Programming – OSCON 2005
has_key()
●
key in dict
●
dict.get(key, default)
Page 139
Effective Python Programming – OSCON 2005
Circular references
●
Not so much of a problem now
(garbage collector)
●
Remember: __del__ stops GC!
Page 140
Effective Python Programming – OSCON 2005
Regular Expressions
●
Should not be the first hammer in your
toolbox
●
Sometimes, a real parser is better
●
If you must use them...
Page 141
Effective Python Programming – OSCON 2005
re.compile()
●
re.compile() returns a compiled
expression
●
much, much faster than re-compiling
each time
●
nicer API, too
Page 142
Effective Python Programming – OSCON 2005
named RE groups
●
Use named RE groups rather than
numbered ones
r = re.compile('(?P<name>[^ ]+) (?P<surname>[^ ]+)')
match = r.match('Anthony Baxter')
match.group('surname')
Page 143
Effective Python Programming – OSCON 2005
Defensive RE programming
●
Check the string matches what you
expect, first
●
Debugging complex RE failures is a
world of hurt
Page 144
Effective Python Programming – OSCON 2005
Efficient Python Programming
●
Making Python Go Fast
Page 145
Effective Python Programming – OSCON 2005
S.A.S. Theatre
●
function calls are slow
Page 146
Effective Python Programming – OSCON 2005
Making your Python code fast
●
dicts, list.sort() are highly tuned
●
globals are slower than locals
●
list.pop(0), list.insert(0, value) are slow
reverse your list, or use collections.deque
●
move fixed code out of the critical path
Page 147
Effective Python Programming – OSCON 2005
profile/hotshot
●
Figure out where the slow bits are
●
Get the code right first (with unit tests!)
and then optimise
Page 148
Effective Python Programming – OSCON 2005
numeric/numarray
●
Insanely optimised array operations
●
If dealing with numbers, use them
Page 149
Effective Python Programming – OSCON 2005
Pyrex
●
Python dialect that's compiled to C
●
Start with straight Python code, add
declarations to use C types
●
Only optimise the hot spots
●
Much easier than trying to write
straight C code extensions
Page 150
Effective Python Programming – OSCON 2005
__slots__
●
Optimisation trick
●
Python objects store attributes in a
dictionary
●
__slots__ is a fixed list
●
reduces memory consumption when
you have many small objects
Page 151
Effective Python Programming – OSCON 2005
__slots__
●
Don't use __slots__ as some sort of
type-checking hack
●
__slots__ and subclassing == hurt
Page 152
Effective Python Programming – OSCON 2005
Tying it all back together
●
Java DOM Node
●
Good example of a bad Python API
Page 153
Effective Python Programming – OSCON 2005
Node.getChildNodes()
●
Returns the child nodes of the current
Node.
●
Either:
Node.childNodes
●
or
Make Node an iterator that iterates
through it's children
Page 154
Effective Python Programming – OSCON 2005
getValue()/setValue()
●
Instead, just use node.value
●
Or use a property if value is computed,
or needs to be checked when set
Page 155
Effective Python Programming – OSCON 2005
isSameNode()
●
Implement a __eq__ method
thisNode == otherNode
●
Note that 'is' might not be right
if you can have two Node instances
pointing at the same part of the DOM
Page 156
Effective Python Programming – OSCON 2005
compareDocumentPosition()
●
Compares Node's document position to
another Node.
●
Instead, implement a .position attribute
that can be compared:
thisNode.position < otherNode.position
●
Or even Node.__lt__, Node.__gt__
Could be a bit too clever/magic
Page 157
Effective Python Programming – OSCON 2005
parent/child reference cycle
●
Remember, a parent child reference
cycle isn't a problem
(So long as Node doesn't implement a
__del__ method!)
●
Still, don't create them unnecessarily
References keep objects alive
Page 158
Effective Python Programming – OSCON 2005
Wrapping Up
●
Write Python code in Python
●
Might involve un-learning some habits
from other languages
●
More information in the notes for these
slides...
Page 159
Effective Python Programming – OSCON 2005
●
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!
1.2. 体验
有多少人注意到手册中这节的内容? 2.3.8 Mapping Types -- classdict
非常正常的函式,好象?但是产生的魔力是惊人的! - 原来 Python 早已内置了无数真正方便广大程序员,可以快捷高效的组织好代码的函式!
1 callDict = {
2 'FOZZIE': showFozzie,
3 'KERMIT': showKermit,
4 }
5 # 然后就可以如此影响各种情况了
6 func = callDict.get("FOZZIE", showUnknownMuppet)
7 func()
8 # 简化版本的..
9 callDict.get("SomeMatterTarget",
10 showUnknownMuppet)()
11
12 def showFozzie():
13 print "showFozzie"
14 def showKermit():
15 print "showKermit"
16 def showUnknownMuppet():
17 print "showUnknownMuppet"
2. 反馈
::-- ZoomQuiet [2007-02-02 02:31:04]
