title: leading underscore in Python class names
body: <p>This question builds on <a href="https://stackoverflow.com/questions/7609508/is-it-a-convention-to-prefix-private-classes-with-underscores">this one asked earlier</a> and also <a href="https://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python">this one</a>, but addresses a more subtle point, specifically, what counts as an "internal class"?</p>
  
  <p>Here's my situation. I'm building a Python library for manipulating MS Office files in which many of the classes are not meant to be constructed externally, yet many of their methods are important parts of the API. For example:</p>
  
  <pre><code>class _Slide(object):
      def add_shape(self):
          ...
  </code></pre>
  
  <p><code>_Slide</code> is not to be constructed externally, as an end-user of the library you get a new slide by calling <code>Presentation.add_slide()</code>. However, once you have a slide you definitely want to be able to call <code>add_shape()</code>. So the method is part of the API but the constructor isn't. This situation arises dozens of times in the library because only the Presentation class has an external/API constructor.</p>
  
  <p>PEP8 is ambiguous on this point, making reference to "internal classes" without elaboration of what counts as an internal class. In this case I suppose one could say the class is "partially  internal".</p>
  
  <p>The problem is I only have two notations to distinguish at least three different situations:</p>
  
  <ol>
  <li>The constructor and "public/API" methods of the class are all available for use.</li>
  <li>The constructor is not to be used, but the "public/API" methods of the class are.</li>
  <li>The class really is internal, has no public API, and I reserve the right to change or remove it in a future release.</li>
  </ol>
  
  <p>I note that from a communications perspective, there is a conflict between clear expression of the external API (library end-user audience) and the internal API (developer audience). To an end user, calling <code>_Slide()</code> is verboten/at-own-risk. However it's a happy member of the internal API and distinct from <code>_random_helper_method()</code> which should only be called from within <code>_Slide()</code>.</p>
  
  <p>Do you have a point of view on this question that might help me? Does convention dictate that I use my "single-leading-underscore" ammunition on class names to fight for clarity in the end-user API or can I feel good about reserving it to communicate to myself and other developers about when a class API is really private and not to be used, for example, by objects outside the module it lives in because it is an implementation detail that might change?</p>
  
  <hr>
  
  <p><strong>UPDATE:</strong> After a few years of further reflection, I've settled into the convention of using a leading underscore when naming classes that are not intended to be accessed <em>as a class</em> outside their module (file). Such access is typically to instantiate an object of that class or to access a class method, etc.</p>
  
  <p>This provides users of the module (often yourself of course :) the basic indicator: "If a class name with a leading underscore appears in an import statement, you're doing something wrong." (Unit test modules are an exception to this rule, such imports may often appear in the unit tests for an "internal" class.)</p>
  
  <p>Note that this is access to the <em>class</em>. Access to an <em>object</em> of that class (type) outside the module, perhaps provided by a factory or whatever, is perfectly fine and perhaps expected. I think this failure to distinguish classes from the objects created from them was what led to my initial confusion.</p>
  
  <p>This convention also has the side benefit of not including these classes when making a <code>from module import *</code> statement. Although I never use these in my own code and recommend avoiding them, it's an appropriate behavior because those class identifiers are not intended to be part of the module interface.</p>
  
  <p>This is my personal "best-practice" after years of trial, and not of course the "right" way. Your mileage may vary.</p>