{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Naming conventions and other good practices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Zen\n", "There are a number of good practices are worth following when programming so that the code is readable and maintanable. Some general principles are illustrated in the Zen of Python, a collection of principles that influences the design of Python programs, but can be applied to programming in general. They are as follows (run the code cell):" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import this" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Keep these principles in mind when programming. This document will try to especially stress good practices for readable code, and hopefully we won't have Computer Scientists making fun of \"Physicist's code\" in the future." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Coding Style\n", "\n", "Having only worked on short, isolated, projects so far, you may not yet realise how often you will end up reusing code. There will often be times when you come back to code that's months - even years - old. The way you've named things will either make this code completely useless, meaning it's actually faster to rewrite the code, or you might be able to edit the code and reuse large bits of it.\n", "\n", "**Always give variables, functions, and classes descriptive names**. Most modern editors have autocomplete, so writing a slightly longer variable name shouldn't take too much longer than a shorter, less readable name. It also has the added benefit that the resulting code will be almost self-documented, although obviously, nothing is as good as good documentation.\n", "\n", "Thanks to Python's lack of static typing, keeping track of the types of arguments that functions take can be a nightmare, as the code will almost certainly expect a certain type of object to be passed for each argument, but it's difficult to tell just by looking at the code. You may be tempted to use Hungarian notation (stating the variable type in the variable name), don't. It's a brittle way to denote types (e.g. you might decide later on that you don't want a vpython vector but rather a numpy array to represent the same data structure, which would mean all your vvec_variables will need to be found and replaced) and makes code less readable. It's better to document the types of variables that a function accepts and returns using comments. Even if you don't do any other documentation, this is a bare minimum which will mark the difference between un-reusable and reusable code.\n", "\n", "To make your code readable to any Python programmer, follow the PEP 8 conventions (Or whatever the mainstream convention is for the language you are using; you should easily find conventions by googling). You can read them in full [here](https://www.python.org/dev/peps/pep-0008/), but here are a few of the most important ones to get you started:" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "run_control": { "frozen": false, "read_only": false } }, "source": [ "#### Naming conventions\n", "\n", "In general, don't use single characters for variable names. In particular, never use the characters 'l' (lychee), 'O' (Orangutan), and 'I' (Iguana) for variable names as they look the same as other characters depending on the font used.\n", "\n", "* Function names should be lower case, with words spearated by underscores, e.g.: function_name\n", "\n", "* Method names follow the same convention as function names: e.g. method_name\n", "\n", "* If you want a function, method, or property to be *private*, prefix the name with an underscore, e.g.: _variable_name _method_name _function_name\n", "\n", "* Instance methods should always use self for the first argument.\n", "\n", "* Class methods should always use cls for the first argument.\n", "\n", "* Constants defined on a module level should be written in all caps with underscores between words, e.g. : MODULE_VARIABLE\n", "\n", "* Class names should use the CapWords convention, e.g.: ClassName\n", "\n", "Don't write lines that are too long. If a line is too long, you can wrap it in brackets, then Python will understand that the lines implicitly continue, e.g.:\n", "\n", " particle = Particle(pos = np.array([-5.,0.,0.]),\n", " v = np.array([0.,0.,0.]),\n", " inv_mass = 1.,\n", " color = [1., 1., 1.],\n", " fixed = True))\n", "\n", "Align continued lines with the start of the bracket.\n", "\n", "We recommend the following structure for programs/modules:\n", "\n", "* Import neccesary libraries\n", "\n", "* Declare functions\n", "\n", "* Declare classes\n", "\n", "* Declare variables\n", "\n", "* Manipulate variables\n", "\n", "The above structure allows one to know what libraries the program is dependent upon immediately and also establishes the \"toolbox\" one can use in the program before the program is itself made. Of course, this structure is not always applicable, e.g. variables may need to be declared later on, but one shoudl strive to keep to such a structure for clean, legible code." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Other good practices\n", "\n", "**As with essays, a little planning goes a long way**. Make a list of the classes and functions you will need before you start programming, for clearer code.\n", "\n", "Try to modularise your code as much as possible: this will mean that portions of your code will be reusable in future projects. To this end, consider the following tips:\n", "\n", "* Avoid global variables: if you have them, you will end up having to copy all of the code, instead of just a function or a class, to get the function or class working correctly. (Don't look at any code written by Sam Garratt)\n", "\n", "* Don't \"Hard-code\" variables: e.g. if you're opening a file, have a variable file_path then open the file at that file path instead of just giving the string for the file path to a function to open a file.\n", "\n", "* Consider Object Oriented Programming: Although not applicable in all situations, one of the motivations for its developement was to make large projects easier by allowing more modular code.\n", "\n", "Premature optimization is the root of all evil. Of course, one should strive to pick an efficient structure for their program, but in general, optimization can come later.\n", "\n", "Don't reinvent the wheel. 9 times out of 10, there will be a library that does what you want to do already. Use it. It will *probably* be faster and safer. Of course, there might be times when you want to learn the algorithm, in which case it's perfectly fine to write your own implementation. However, when you're writing code not to learn but to use, use the external library." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.2" }, "widgets": { "state": {}, "version": "1.1.2" } }, "nbformat": 4, "nbformat_minor": 0 }