[Tutor] _ vs. _name vs. __name vs. name_ vs. __name__ usages

Cameron Simpson cs at zip.com.au
Tue Jul 28 01:42:13 CEST 2015


On 25Jul2015 16:08, boB Stepp <robertvstepp at gmail.com> wrote:
>After having a long discussion with my wife on her user requirements,
>I am convinced that an OO approach is required.  Which is just as well
>as that has been one of my next areas of learning to do.  I am
>currently reading "Python 3 Object Oriented Programming" by Dusty
>Phillips, which so far seems to be a reasonably good text.  This has
>led me to the subject line topics.
>
>From my understandings to date:

Broadly everything you have said is correct.

>1) A single underscore is used conventionally for a "throw-away"
>variable, such as a loop index for which the index value is not
>actually used in a subsequent calculation.

Yes, but there are some problems. Some don't like it, and it can conflict with 
other uses. I use it very rarely, almost only ever in very simple list 
comprehensions, such as this real example:

  self.hashlist = [None for _ in range(maxchunks)]

which primes a list of None values.

Using it in a wider context like a loop has the same issues as any other 
"trite" variable name: that you will reuse it later and forget that it is 
either already in play (eg nested loops) or already initialised (eg code later 
break because of some presumption it is not set up).

It is almost always better, if only for readability, to pick a sensible name, 
like "i", even if it is not used. A short name like "i" pretty much says "this 
is used only here, because otherwise I would have used a longer name that has 
more context".

Of course, the flip side of that is that "_" _is_ the name that says "not used 
elsewhere", and thus if you use it in in an expression t should scream 
"mistake" at you. So this:

  [ (i,) for i in range(10) ]

to make a list of tuples (made up example) should not be used with "_" instead, 
as "i" does get used.

So yes, correct, but many people use it very sparingly and some avoid it 
altogether.

>2) _name is used inside class methods to indicate that the
>programmer's intention is that this name should only be accessed
>internally by that particular class.  Other supposedly "adult" Python
>programmers will attempt to respect this original intent if they use
>my code.

Or by cooperating classes. But only _closely_ cooperating classes that have 
knowledge of your first class' internals, usually because they muck with them 
directly.  Basicly, a _name is held to be part of the private API, and subject 
to change.

So code which is prepared to be broken by changes might use it, such as if you 
have a pair of classes which both muck _directly_ with some shared data 
structure.

Note than in pure OO one class never mucks with another class' internals; they 
only ever communicate via methods.

>3) __name invokes Python's name mangling mechanism.  The intent of
>this usage is to not allow subclasses of the class containing __name
>to access this name, and to add additional emphasis to future users of
>my code that this name is meant to be strictly hands-off.

Yeah. I have pretty much ceased using this. It causes pain and doesn't fulling 
solve the problems.

The usual use case is subclassing:

  class Shape(object):

    def __init__(name):
      self.name = name
      self.__count = 0

    def inc(self):
      self.__count += 1

  class Cube(Shape):

    def __init__(name):
      Shape.__init__(name)
      self.__count = 6

    def add_face(self):
      self.__count += 1

Internally there two classes work on "__Shape_count" and "__Cube_count", and 
thus avoid stepping on each others' toes, because although each wants a counter 
with a nice simple name, they mean very different things with it. So you Cube 
class has two separate counters.

But the names are arguably uglier and harder to type.

Also, consider this:

  from my_geometry_module import Shape as UrShape

  class Shape(UrShape):

    def __init__(self, name):
      UrShape.__init__(name)
      self.__count = 5

    def bfmi(self):
      self.__count -= 1

  class Pyramid(Shape):
    ...

Here, your local "Shape" class will _also_ use "__Shape_count", and _will_ have 
trouble. So this system is not totally robust. While the example above is 
contrived, a deeper nesting of classes might easily have the same issue because 
the final class may not be aware that a class of the same name is already in 
use higher up the chain.

>4) name_ is used when one is "forced" to use one of Python's reserved
>words as a name.

Yes, quite command. Also for predefined names as well as reserved names. My 
commonest use is the name "type", which is no a reserved word (i.e. special in 
the language grammar, like "if") but predefined as the "what is the type of 
this object" function. I've got a few objects floating around where a ".type" 
attribute is a natural name to indicate their flavour. That works just fine.  
But when I want to access the object, "type" is also a natural name for the 
parameter:

  def check_type(self, type):
    return self.type == type

While that works, it means you have lost access to the predefined Python type() 
function inside that bit of code. Which can be bad. Even if you do not use the 
function, it makes your code confusing for other programmers (== you several 
months later) because they have an expectation of its meaning.

Way of addressing this all involve just using another name. Common ways include 
"name_", "n" (trivial short term variable) or a misspelling. For example, 
saying "klass" instead of "class".

>5) __name__ is meant to be used only by the creators of Python for
>their special built-in methods, such as __init__, __new__, etc.

Yes, but in the sense that they have predefined meanings. If you are 
implementing a mapping (a class that has methods and access like a dictionary), 
you will need to define methods using these names to implement the API.

So don't make up your own!

>Are my understandings above correct or flawed?

Yes.

>For (3), it seems to me that one would normally be able to use the
>simpler _name construction from (2).  What would be a best-practice
>example of when name mangling *should* be used?

Well, people rarely use _name as a function parameter, unless it is a 
private/secret parameter for special internal use.

So I would write this:

  def check_type(self, type_):
    return self.type == type_

instead of using "_type". because "type_" here is a _public_ parameter for 
people to use. Using "_type" would mislead.

>Likewise, it seems that normally (4) should never be needed, though I
>have a feeling that I have seen something in tkinter recently that
>suggests some exceptions, but I cannot (yet) bring it to mind.

(4) is never required, but is often convenient.

>And for (5), surely I should never violate this one?  It seems that in
>some future edition of Python they might add any particular __name__
>that I might try to use presently in their future version of Python
>(however miniscule that possibility might actually be).

Yes: don't make up new __name__s. But you will _implement_ some __name__s at 
some point.

Cheers,
Cameron Simpson <cs at zip.com.au>

On the one hand I knew that programs could have a compelling and deep logical
beauty, on the other hand I was forced to admit that most programs are
presented in a way fit for mechanical execution, but even if of any beauty at
all, totally unfit for human appreciation.      - Edsger W. Dijkstra


More information about the Tutor mailing list