Stumbling Toward 'Awesomeness'

A Technical Art Blog

Monday, February 5, 2018

Python Style Guidelines: Consistency is King

I wanted to touch on something that comes up every once in a while: The PEP8 Style Guide. When you’re first getting into Python, you are messy as hell, and as you gain more experience, you start understanding the need to adhere to basic standards for code style. However, just at that moment, I see people completely miss the point of PEP8, and go down this path of assuming that anyone not adhering to PEP8 is doing it wrong.

That’s not the case, and without really understanding PEP8, you could easily fall into this trap.

PEP8 Is About One Thing

PEP8, as defined by itself is about one thing over all CONSISTENCY. Literally the FIRST THING PEP8 says after the Introduction this:

But people don’t really want to pay attention to that, I mean you’re looking at the PEP8 docs to be told how to write code, not that you might be in a situation where you should ignore their standards. But the most important message they impart is to be CONSISTENT.

Python Application APIs

In the VFX and games industry, most of the Python we write is inside existing applications through exposed C++ APIs that have been wrapped in Python. Often people wonder why these professional applications don’t adhere to the PEP8 Style Guide. The answer is simple, they are wrapping existing C++ functions, for CONSISTENCY they use the same camelCase function name as in C++, not lowercase_underscore following PEP8. But why?

  • It allows someone who knows the C++ function to immediately know the Python function
  • It allows a user who is accessing a new method added to an existing class to not have to wonder about it’s naming
  • In documentation, the often human-written explanations of functionality are often completely usable for Python docs

At Crytek, when we implemented Python exposure in the engine, we had to think about this and I noticed that almost all applications with C++ Python APIs were consistent with the C++ style/naming. Here are some examples:

  • Maya: cmds.setAttr()
  • 3dsMax: GetLengthSquared()
  • CryEngine: Alembic.playSequence()
  • PySide: QtGui.QMainWindow.setCentralWidget()
  • Modo: scene.ItemLookup()
  • Houdini: point.setAttribValue()
  • MotionBuilder: actor.setDefinitionScaleVector()
  • Substance: sbsexporter.getExportedDependencies()

Are all these developers stupid for ignoring the ‘Jesus book’ of Python Coding Standards? No, they are actually following it! Remember: CONSISTENCY!

Interpretation of The Good Book

Let’s take a look at some times when you should or shouldn’t follow the good book. These are just my take on things, I would love to hear your take in the comments. Also, this post mainly centers on naming standards, it’s usually best to decide as a team which PEP8 rules you want to follow and which don’t make sense.

I am generating a python API that wraps my C++ code

Be consistent with your naming standards that are already set. Even Python itself has multiple libs that don’t follow PEP naming just to be consistent with existing work. This one was covered above, so I’ll move on.

I am writing code that fits within an existing Python API

Be consistent with that API. If you’re in Maya or using PySide, you’re forced to use their function names. Please don’t have half your code with their function names and then half the code with your own PEP8 function names, this is really inconsistent. Not to mention when you override or reimpelent existing functions,  you’ll find yourself typing something like “on_close”. Another annoyance will be style enforcement in IDEs, if you use PEP8 you are probably enabling style enforcement, and you’ll a ton of false warnings from the API you’re using.

I am writing a standalone Python application or package

Use the PEP8 Styleguide if it makes sense. But don’t feel the need to refactor all your code, again, just take a look at Python’s own threading or logging modules, they don’t adhere to their own standards because it didn’t make sense.

ADDITIONAL NOTE:
I was pointed to the blog of Eric Husler, a veteran VFX and game pipeline programmer who covered this very topic in his post PyQT Coding Style Guidelines, his sentiments also follow the above:

“While you may be programming in Python, you’re creating Qt classes – inheriting their conventions along the way. When adding a new method, you should keep the consistency of Qt – that way someone working with your widgets doesn’t have to think about whether a method came from Python, and so use underscores, or came from Qt itself, and so use camel humps.”

He offered good examples of what we are discussing above, here is a widget with custom functions consistent with QT:

widget = MyWidget()
widget.setWindowTitle('Testng')
widget.loadItems()
widget.setMaximumWidth(100)
widget.refreshResults()

Here is a widget that has custom functions that adhere to PEP8 style but are inconsistent with QT:

widget = MyWidget()
widget.setWindowTitle('Testing')
widget.load_items()
widget.setMaximumWidth(100)
widget.refresh_results()

 

 

posted by Chris at 9:39 AM  

1 Comment »

  1. Thanks for postingt his, you wouldn’t believe how many engineers get this wrong. You would think that they would look at how the rest of the world does it, but I guess not many engineers use Python APIs inside other applications.

    Comment by JS — 2018/02/13 @ 6:37 PM

RSS feed for comments on this post. TrackBack URI

Leave a comment

Powered by WordPress