Python scripts aren’t supposed to be works of art, but it’s rare to find one that’s instantly usable. Here are 10 things I wish all scripts would do:
10. Set correct permissions
A script that doesn’t have proper execution permissions makes me very angry. Set
chmod a+x so anybody can run the script (unless it requires root permissions).
9. Invoke the correct Python
You didn’t put a shebang at the top of your script? Well, that’s fine, we’ll just put the right one in. Oh wait, you put a shebang, but it’s
#!/usr/bin/python instead of
#!/usr/bin/env python at the top? Shame on you, my environment knows which Python I want to use and you just slapped it in the face by telling it to run my awful, unloved, un-updated system Python.
8. Use top-level docstrings
Ray Hettinger called it the module’s “elevator pitch”. All you need to do, at the top of the script, is write a docstring that says something useful about the script:
""" Ingests pizza, coffee, and internet memes revolving around cats; produces code. Does not currently support being social. """
Not only is this good form; it’ll be super-useful later (you’ll see).
7. Implement the primary functionality as a self-contained function with reasonable arguments
Sure, it’s only a script; how modular does the code need to be? The answer: “writing good code isn’t an activity; it’s a lifestyle”. If your script was worth writing in the first place, won’t it be worth testing, documenting, and possibly putting into a library later? And won’t others have a much easier time understanding and maintaining it if functions were easy to follow in the first place?
6. Use OptionParser or, better yet, ArgumentParser
If you’re still using command-line parsing code like
if len(sys.argv) < 3, you need to put away your scooter and go get a monster truck that can take care of required arguments, default values, and help descriptions with roaring efficiency. For holdouts who insist on sticking with Python 2.6 and earlier, there’s OptionParser; for everyone else, there’s the incredibly awesome ArgumentParser that makes my nose bleed with parsy parsingness.
5. Set description to the top-level docstring
Remember that lovely top-level “elevator pitch” you put at the top of the file? You can access it anywhere else in the script as
__doc__. Use it in the usage description that gets printed automatically when the user runs your script with the “-h” or “–help” flags:
parser = optparse.OptionParser(description=__doc__)
parser = argparse.ArgumentParser(description=__doc__)
4. Use the argument default help formatter
Don’t you want your users to see the defaults for everything when they print help messages? Of course you do. Use the argparse formatter that does this:
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
if __name__ == '__main__' correctly
There should literally be nothing besides variable declarations and function imports outside of function declarations and the
if __name__ == '__main__' block. The rule of thumb is: if a user imports your script, your script shouldn’t actually run any code until the user explicitly asks it to.
2. Allow wildcards for file arguments
With ArgumentParser, it’s really easy to create argument types where users can specify wildcards. All you have to do is set
nargs to “+” when you add the argument:
parser.add_argument(type=str, help='File sources', nargs="+", metavar='', dest='sources')
After you run the parser,
sources will be a list of all files that match the wildcard that the user entered. This makes your script super-intuitive and easy for everyday use. Users will give you candy.
1. For heaven’s sakes, actually work
Ok fine, every item above was a “nice-to-have” feature that obviously doesn’t trump the most important of all: actually working. But I’ve found that, if a developer put in the time on #2-10, it’s pretty likely that he/she also nailed #1. Let’s all work on our script writing mojo.