When writing your own scripts python is great for new developers to pick up and become productive, but you can also pick up odd habits or at least write scripts that are not easy for others to understand.
For your own work this is of course fine, but if you want to collaborate with others or have your work included with blender there are practices we encourage.
For Blender/Python development we have chosen to follow python suggested style guide to avoid mixing styles amongst our own scripts and make it easier to use python scripts from other projects.
* pep8 also defines that lines should not exceed 79 characters, we felt this is too restrictive so this is optional per script.
Periodically we run checks for pep8 compliance on blender scripts, for scripts to be included in this check add this line as a comment at the top of the script.
In Python there are some handy list functions that save you having to search through the list.
Even though you're not looping on the list data **python is**, so you need to be aware of functions that will slow down your script by searching the whole list.
In python we can add and remove from a list, This is slower when the list length is modified, especially at the start of the list, since all the data after the index of modification needs to be moved up or down 1 place.
The most simple way to add onto the end of the list is to use ``my_list.append(list_item)`` or ``my_list.extend(some_list)`` and the fastest way to remove an item is ``my_list.pop()`` or ``del my_list[-1]``.
To use an index you can use ``my_list.insert(index, list_item)`` or ``list.pop(index)`` for list removal, but these are slower.
Sometimes its faster (but more memory hungry) to just rebuild the list.
Say you want to remove all triangle faces in a list.
Rather than...
..code-block:: python
faces = mesh.faces[:] # make a list copy of the meshes faces
f_idx = len(faces) # Loop backwards
while f_idx: # while the value is not 0
f_idx -= 1
if len(faces[f_idx].vertices) == 3:
faces.pop(f_idx) # remove the triangle
It's faster to build a new list with list comprehension.
..code-block:: python
faces = [f for f in mesh.faces if len(f.vertices) != 3]
Adding List Items
^^^^^^^^^^^^^^^^^
If you have a list that you want to add onto another list, rather then...
Note that insert can be used when needed, but it is slower than append especially when inserting at the start of a long list.
This example shows a very sub-optimal way of making a reversed list.
..code-block:: python
reverse_list = []
for list_item in some_list:
reverse_list.insert(0, list_item)
Removing List Items
^^^^^^^^^^^^^^^^^^^
Use ``my_list.pop(index)`` rather than ``my_list.remove(list_item)``
This requires you to have the index of the list item but is faster since ``remove()`` will search the list.
Here is an example of how to remove items in 1 loop, removing the last items first, which is faster (as explained above).
..code-block:: python
list_index = len(my_list)
while list_index:
list_index -= 1
if my_list[list_index].some_test_attribute == 1:
my_list.pop(list_index)
This example shows a fast way of removing items, for use in cases were where you can alter the list order without breaking the scripts functionality. This works by swapping 2 list items, so the item you remove is always last.
When passing a list/dictionary to a function, it is faster to have the function modify the list rather then returning a new list so python doesn't have to duplicate the list in memory.
join is fastest on many strings, string formatting is quite fast too (better for converting data types). String arithmetic is slowest.
Parsing Strings (Import/Exporting)
----------------------------------
Since many file formats are ASCII, the way you parse/export strings can make a large difference in how fast your script runs.
When importing strings to make into blender there are a few ways to parse the string.
Parsing Numbers
^^^^^^^^^^^^^^^
Use ``float(string)`` rather than ``eval(string)``, if you know the value will be an int then ``int(string)``, float() will work for an int too but its faster to read ints with int().
However **try** is significantly slower then an **if** since an exception has to be set each time, so avoid using **try** in areas of your code that execute in a loop and runs many times.
Python has two ways to compare values ``a == b`` and ``a is b``, The difference is that ``==`` may run the objects comparison function ``__cmp__()`` where as ``is`` compares identity, that both variables reference the same item in memory.
In cases where you know you are checking for the same value which is referenced from multiple places, ``is`` is faster.