# 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 BaseException:
       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*
  - Rather than passed on

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

- Spot bug here:

    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)

- Correct way

    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

- Bad idea!

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
  - 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
  - ...but not always.
- 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)

- Better

    # 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
  - os.path.join especially
- 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

- http://aspn.activestate.com/ASPN/Python/Reference/Products/ActivePython/howtos/doanddont/doanddont.html
- http://www.amk.ca/python/writing/warts.html
- http://www.python.org/doc/essays/styleguide.html

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

- Here's what not to do:

    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.