Idioms and Anti-Idioms in Python
Idioms and Anti-Idioms, AKA Do and Don't
- Welcome
- Gimmick -- Charmed quotes
Prue (Something Wicca This Way Comes, season 1) -- No, we are not supposed to use our powers
Python
- Few gotchas...
- ...but not zero
- Most are easy to avoid...
- ...if you know about them.
Prue (Something Wicca This Way Comes, season 1) -- Uh, it doesn't work out there either.
Exceptions
- Primary method of dealing with errors
- Flexible
- Good opportunity to shoot yourself in foot...
- ...without knowing about it (bug only shows up rarely.)
Leo (Paige From the Past, season 4) -- You have to [...] Paige. No exceptions.
Exceptions -- Catching Too Much
- Classical case: 'except:'
- Will catch anything
- Including most bugs...
- NameError, AttributeError...
Piper (Charmed Again, season 4) -- Okay, well this is way too much for me to handle.
Exceptions -- Catching Too Much -- Example
try:
f = opne("file")
except:
sys.exit("no such file")
Piper (Charmed Again, season 4) -- Way too much.
Exceptions -- Catching Too Soon
- The slogan:
- Don't catch errors you can do nothing about
- Catching exceptions should by the 'user'
- The point where the value is *used*
Phoebe (Knight to Remember, season 4) -- Maybe it's just too soon.
Exceptions -- Catching Too Soon -- Example
def readlinesfromfile(file):
try:
return open(file).readlines()
except IOError:
pass # do what?
- What can we do?
- Return empty list? bad
- Print warning? what if it's one of several possibilities
- Exit? NO!
- Raise our own exception? Losing information
Paige (Knight to Remember, season 4) -- I'm already a little late.
Catching multiple exceptions
try:
fp = open("file")
except IOError, OSError:
print "could not open file"
Paige (Knight to Remember, season 4) -- Because I've got too many responsibilities
Catching multiple exceptions (cont'd)
- Bug:
- Only IOError gets caught...
- and exception value is put in OSError
- But most exceptions are IOError :(
- Likely to not discover this bug
Piper (Knight to Remember, season 4) -- Alright! Calm down!
Catching multiple exceptions (cont'd 2)
try:
fp = open("file")
except (IOError, OSError):
print "could not open file"
Phoebe (Knight to Remember, season 4) -- Besides that, maybe we can help
Catching NameError
try:
import foo
except ImportError:
pass
try:
foo.Function()
except NameError:
pass # some replacement
Piper (Morality Bites, season 4) -- That's OK, I forgot your name too.
Catching NameError (cont'd)
try:
import foo
except ImportError:
foo = None
if foo is not None:
foo.Function()
else:
pass # some replacement
- If foo.Function() sometimes has a NameError, we won't mask it...
- ...or if we misspell 'foo'
Anne (Morality Bites, season 4) -- Oh, right, sorry.
Importing Modules -- A Review
- 'import module'
- 'from module import name1, name2'
- Only imports once (or does it?)
Phoebe (Animal Pragmatism, season 2) -- Rome was not built in a day,
Importing __main__
- __main__ is where the 'script' is executed
- Avoid the temptation to import __main__
- Put common function in a named module
- Then your code will be more useful
Piper (Animal Pragmatism, season 2) -- And why mess with a good thing?
Importing a File Twice
- But it can't be, can it?
- Importing a script into itself
# file: hello.py
import hello
class Foo: pass
- Two 'Foo's, same definition, different class!
- If your sys.path includes packages...
- ...you can import a module once from a package and once plain
Phoebe (Which Prue Is It, Anyway?, season 1) -- Okay, which one of you is the real Prue?
Importing *
- Don't do it
- Classic mistake:
from os import *
fp = open("file") # works
fp.readline() # fails with a weird error...?
- os.open returns a file descriptor (number)
Pink Prue (Which Prue Is It, Anyway?, season 1) -- So, um, what did I do now?
Importing * Inside Functions
- Just invalid Python...
- ...but happens to work in 1.5.2...
- ...and sometimes in 2.1...
- ...never in 2.2.
- Just Say No
Pink Prue (Which Prue Is It, Anyway?, season 1) -- What ever it is, I have an alibi.
Importing Names
- from foo import name1, name2
- Not a bad idea always
- But be careful of repercussions:
- modules sometimes change things inside
- You won't see those changes
- Opportunity for inconsistency!
Real Prue (Which Prue Is It, Anyway?, season 1) -- Because I still have to work here when all of this is over.
Reloading
- reload(module) -- reread module from file
- Useful in long running processes?
- Doesn't play nice with 'from import name'
- Beware of exceptions: the new classes are different from old classes
Real Prue (Which Prue Is It, Anyway?, season 1) -- Don't worry I'm never casting that spell again.
exec, execfile and eval
- Execute arbitrary Python code
- No-cost scripting language for applications
- But easy to shoot one's self in the foot
Reporter (Morality Bites, season 2) -- More news on the execution of Phoebe Halliwell coming up.
exec, execfile and eval -- Modify namespaces
- They modify the namespace they're in
- Depends on global vs. inside functions
- Use with care -- or with explicit dictionaries
Nathaniel (Morality Bites, season 2) -- Executions are a bitch to plan.
exec, execfile and eval -- Inside functions
- Unadorned exec is invalid inside functions
- execfile and eval play badly with local var. optimisation
- Always use with explicit dictionary
Nathaniel (Morality Bites, season 2) -- Phoebe, what is this? An attempt to stay your execution?
Conclusion: recommended usage
- d={};exec "code" in d
- d={};execfile("file", d)
- d={};eval("expression", d)
- Sometimes useful to pre-populate dictionary
Phoebe (Morality Bites, season 2) -- Just because you don't understand something, doesn't make it evil.
exec, execfile and eval -- Restricted Execution (Don't)
- rexec never was audited
- History of holes
- Dangerous to allow arbitrary code
- DoS attacks not defended against at all
- Recursion
Leo (Morality Bites, season 2) -- Nobody's gonna rescue you.
Syntax
- Python syntax regular and nice...
- ...but not perfect.
- Some care needed.
Prue (Morality Bites, season 2) -- You know, we can still make the good things happen.
Syntax -- Tabs and Spaces
- Use Tabs
- Or use spaces
- But don't mix them...
- ...ever!
- Invites bugs
Prue (The Painted World, season 2) -- We've seen so many bizarre things.
Syntax -- Backslash Continuations
# Extra newline
r = 1 \
+2
# Missing backslash in long series
r = 1 \
+2 \
+3 \
+4
+5 \
+6
- Both *silently* do the wrong things
Syntax -- Backslash Continuations (cont'd)
# Extra newline
r = (1
+2)
# Long series
r = (1
+2
+3
+4
+5
+6)
Prue (The Painted World, season 2) -- Uh, what just happened here?
Hand Hacking Batteries
- Don't write os.path functions yourself
- min, max
- urlparse
- Skim through modules list. A lot.
Prue (Animal Pragmatism, season 2) -- Well, we didn't find anything in the Book Of Shadows.
Further Reading
Phoebe (The Painted World, season 2) -- I think you'll find me pretty knowledgeable about all areas
Questions?
Piper (The Painted World, season 2) -- You're like ask rainman.com
Bonus Slides
Phoebe (The Painted World, season 2) -- Oh, and P.S. there will be no personal gain.
Packages and __init__.py
- Packages are determined by __init__.py files
- Temptation to put code in __init__.py
- But two namespaces mix: __init__'s and filesystem's
- Put comments, docstring and __all__
Piper (Animal Pragmatism, season 2) -- It's a package. One I would like to share with you.
Type Checking
- Python's typing is highly dynamic
- Capability-based, not class-based
- Explicit type checks hurt code usefulness
- (common use -- proxies, for testing)
Phoebe (Black as Cole, season 2) -- I never thought of myself as the marrying type
Type Checking -- Example
class Foo:
def __init__(self, i):
if type(i) is types.StringType:
self.content = open(i).readlines()
elif type(i) is types.ListType:
self.content = i
- (inspired from a question on #python)
- More badness than you can shake a stick at.
Phoebe (Muse to My Ears, season 4) -- You're an artistic, creative type.
Type Checking -- Example -- Fixed
class Foo:
pass
class FooFromFile(Foo):
def __init__(self, filename):
self.content = open(filename).readlines()
class FooFromList(Foo):
def __init__(self, list):
self.content = list
Phoebe (Muse to My Ears, season 4) -- You see how well this worked out?
Private __Attributes
- Useful in deep hierarchies to keep attributes separate
- Mangle only class name -- *not* module name
- Makes it harder to test
- Makes it harder to hand-hack for debugging
Tessa (Animal Pragmatism, season 2) -- Maybe it's our fault because we tried to make them into something they're not.
Using Mutable Default Arguments
def foo(l=[]):
l.append(5);return l
- Will modify the same list.
- If you want that -- use object, class, not that hack.
def foo(l=None):
if l is None: l=[]
l.append(5);return l
Snake guy (Animal Pragmatism, season 2) --
You two are acting like nothing's changed.