diff doc/v2_planning/API_coding_style.txt @ 1159:531e77fb67f2

coding_style: Moved more elements to official 'API'
author Olivier Delalleau <delallea@iro>
date Fri, 17 Sep 2010 12:05:14 -0400
parents d7192e52653e
children 4f1b9e0a1377
line wrap: on
line diff
--- a/doc/v2_planning/API_coding_style.txt	Fri Sep 17 11:21:15 2010 -0400
+++ b/doc/v2_planning/API_coding_style.txt	Fri Sep 17 12:05:14 2010 -0400
@@ -63,14 +63,35 @@
 We emphasize here a few important topics that are found in the official
 guidelines:
 
+    * Only use ASCII characters in code files.
+
+    * Code indent must be done with four blank characters (no tabs).
+
+    * Limit lines to 79 characters.
+
+    * Naming conventions: ``ClassName``, ``TOP_LEVEL_CONSTANT``,
+      ``everything_else``.
+
+    * Comments should start with a capital letter (unless the first word is a
+      code identifier) and end with a period (short inline comments may skip
+      the period at the end).
+
+    * Imports should be listed in alphabetical order. It makes it easier to
+      verify that something is imported, and avoids duplicated imports.
+
+    * Use absolute imports only. This is compatible across a wider range of
+      Python versions, and avoids confusion about what is being
+      imported.
+
     * Avoid using lists if all you care about is iterating on something. Using
       lists:
-        - uses more memory (and possibly more CPU if the code may break out of
-          the iteration),
-        - can lead to ugly code when converted to Python 3 with 2to3,
-        - can have a different behavior if evaluating elements in the list has
-          side effects (if you want these side effects, make it explicit by
-          assigning the list to some variable before iterating on it).
+
+         - uses more memory (and possibly more CPU if the code may break out of
+           the iteration),
+         - can lead to ugly code when converted to Python 3 with 2to3,
+         - can have a different behavior if evaluating elements in the list has
+           side effects (if you want these side effects, make it explicit by
+           assigning the list to some variable before iterating on it).
 
       +------------------------+------------------------+
       | Iterative version      |    List version        |
@@ -100,7 +121,7 @@
         for f_x in imap(f, x):
             ...
         all_f_x = map(f, x)
-        map(f, x)
+        map(f, x)   # f has some side effect.
         # Bad.
         for element in map(f, x):
             ...
@@ -132,12 +153,89 @@
         has_key = my_dict.has_key(key)
         has_substring = my_string.find(substring) >= 0
 
+    * Do not use mutable arguments as default values. Instead, use a helper
+      function (conditional expressions are forbidden at this point, see
+      below).
+
+      .. code-block:: python
+
+        # Good.
+        def f(array=None):
+            array = pylearn.if_none(array, [])
+            ...
+        # Bad.
+        def f(array=[]): # Dangerous if `array` is modified down the road.
+            ...
+
+    * Use a leading underscore '_' in names of internal attributes / methods,
+      but avoid the double underscore '__' unless you know what you are
+      doing.
+
 
 Additional Recommendations
 --------------------------
 
 Things you should do even if they are not listed in official guidelines:
 
+    * No conditional expression (not supported in Python 2.4). These are
+      expressions of the form ``x = y if condition else z``.
+
+    * Use ``//`` for integer division and ``/ float(...)`` if you want the
+      floating point operation (for readability and compatibility across all
+      versions of Python).
+
+      .. code-block:: python
+
+        # Good.
+        n_samples_per_split = n_samples // n_splits
+        mean_x = sum(x) / float(len(x))
+        # Bad.
+        n_samples_per_split = n_samples / n_splits
+        mean_x = sum(x) / len(x)
+
+    * Always raise an exception with ``raise MyException(args)`` where ``MyException``
+      inherits from ``Exception``. This is required for compatibility across
+      all versions of Python.
+
+      .. code-block:: python
+
+        # Good.
+        raise NotImplementedError('The Pylearn team is too lazy.')
+        # Bad.
+        raise NotImplementedError, 'The Pylearn team is too lazy.'
+        raise 'The Pylearn team is too lazy to implement this.'
+
+    * Use either ``try ... except`` or ``try ... finally``, but do not mix
+      ``except`` with ``finally`` (which is not supported in Python 2.4).
+      You can however embed one into the other to mimic the ``try ... except ...
+      finally`` behavior.
+
+      .. code-block:: python
+    
+        # Good.
+        try:
+            try:
+                something_that_may_fail()
+            except SomeError:
+                do_something_if_it_failed()
+        finally:
+            always_do_this_regardless_of_what_happened()
+        # Bad.
+        try:
+            something_that_may_fail()
+        except SomeError:
+            do_something_if_it_failed()
+        finally:
+            always_do_this_regardless_of_what_happened()
+
+    * Do not use the ``all`` and ``any`` builtin functions (they are not supported
+      in Python 2.4). Instead, import them from ``theano.gof.python25`` (or
+      use ``numpy.all`` / ``numpy.any`` for array data).
+
+    * Do not use the ``hashlib`` module (not supported in Python 2.4). We will
+      probably provide a wrapper around it to be compatible with all Python
+      versions.
+
     * Avoid backslashes whenever possible. They make it more
       difficult to edit code, and they are ugly (as well as potentially
       dangerous if there are trailing white spaces).
@@ -193,6 +291,50 @@
                                            my_everything]:
             ...
 
+    * Use the ``key`` argument instead of ``cmp`` when sorting (for Python 3
+      compatibility).
+
+      .. code-block:: python
+
+        # Good.
+        my_list.sort(key=abs)
+        # Bad.
+        my_list.sort(cmp=lambda x, y: cmp(abs(x), abs(y)))
+
+    * Whenever you read / write binary files, specify it in the mode ('rb' for
+      reading, 'wb' for writing). This is important for cross-platform and
+      Python 3 compatibility (e.g. when pickling / unpickling objects).
+
+      .. code-block:: python
+
+        # Good.
+        cPickle.dump(obj, open('my_obj.pkl', 'wb', protocol=-1))
+        # Bad.
+        cPickle.dump(obj, open('my_obj.pkl', 'w', protocol=-1))
+
+    * Avoid tuple parameter unpacking as it can lead to very ugly code when
+      converting to Python 3.
+
+      .. code-block:: python
+
+        # Good.
+        def f(x, y_z):
+            y, z = y_z
+            ...
+        # Bad.
+        def f(x, (y, z)):
+            ...
+
+    * Only use ``cPickle``, not ``pickle`` (except for debugging purpose since
+      error messages from ``pickle`` are sometimes easier to understand).
+
+    * A script's only top-level code should be something like:
+
+      .. code-block:: python
+
+        if __name__ == '__main__':
+            sys.exit(main())
+
 
 The ``logging`` Module vs. the ``warning`` Module
 =================================================