Why do only callable objects get a __name__?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Tue Nov 19 00:21:15 CET 2013


On Mon, 18 Nov 2013 12:13:42 -0800, John Ladasky wrote:

> I just created an object using collections.namedtuple, and was surprised
> to discover that it didn't have a __name__

I'm not sure why you're surprised. Most objects don't have names, 
including regular tuples:

py> some_tuple = (23, 42)
py> some_tuple.__name__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute '__name__'



Remember, Python has two distinct concepts of names: the name that an 
object knows itself by, and the variable name that it is bound to. 
Objects may be bound to zero, one, or more variable names. Here are some 
examples of the later:

print 42  # zero name
x = 42  # one name
x = y = z = 42  # three names

It simply isn't practical or meaningful to go backwards from the object 
42 to the variable name(s) it is bound to -- in the first example, there 
is no variable name at all; in the third, there are three. Even if you 
wanted to do it, it would be a performance killer. So if you have any 
thought that "the name of an object" should be the name of the variable, 
scrub that from your head, it will never fly.

That leaves us with the name that objects know themselves by. For the 
rest of this post, any time I talk about a name, I always mean the name 
an object knows itself by, and never the variable name it is bound to (if 
there is such a variable name).

As a general rule, names aren't meaningful or useful for objects. To 
start with, how would you give it a name, what syntax would you use? What 
would you expect these examples to print?

import random
random.random().__name__

data = [23, 17, 99, 42]
print data[1].__name__


In general, objects are *anonymous* -- they have no inherent name. 
Instances come into being in all sorts of ways, they live, they die, 
they're garbage-collected by the compiler. They have no need for 
individual names, and no way to be given one.

But if you insist on giving them one, you can give it a go. But I 
guarantee that (1) you'll find it a lot less useful, and (2) a lot more 
inconvenient than you expected:

class NamedList(list):
    def __new__(cls, name, *args):
        obj = super(NamedList, cls).__new__(cls, *args)
        obj.__name__ = name
        return obj
    def __init__(self, name, *args):
        super(NamedList, self).__init__(*args)

py> print NamedList("fred", [1, 2, 3, 4, 5]).__name__
fred


So it works, but what a drag, and you don't get much for the effort.

The three obvious exceptions are:

- modules
- classes/types
- functions/methods

In the first case, modules, there is an obvious interpretation of what 
the name ought to be: the filename minus the extension. Since the module 
knows where it came from, it can know it's own name:

py> import re
py> re.__name__
're'


Even if you bind the module object to a different variable name, it knows 
its own inherent name:

py> import math as fibble
py> print fibble.__name__
math


For functions and classes, such names are especially useful, for 
debugging and error messages:

py> def one_over(x):
...     return 1.0/x
...
py> one_over(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in one_over
ZeroDivisionError: float division by zero


Notice the second last line, where it gives the function's name? That 
would be impossible if callables (functions, classes) didn't know their 
own name. You'd get something like:

File "<stdin>", line 2, in <function object at 0xb7ea7a04>

which would be useless for debugging. So how fortunately that there is 
obvious and simple syntax for setting the name of functions and classes:

class This_Is_The_Class_Name:
    def this_is_the_function_name(self): 
        ...



> -- even though something that
> behaves like __name__ is clearly accessible and printable.  Here's some
> minimal Python 3.3.2 code and output:
> 
> =================================================
> 
> from collections import namedtuple
> 
> MyNamedTupleClass = namedtuple("ANamedTuple", ("foo", "bar"))

Here you define a class, called "ANamedTuple". Unfortunately, it doesn't 
use the standard class syntax, a minor limitation and annoyance of 
namedtuples, and so you're forced to give the class name "ANamedTuple" 
explicitly as an argument to the function call. But the important thing 
here is that it is a class. 


> nt = MyNamedTupleClass(1,2)

nt, on the other hand, is a specific instance of that class. You might 
have hundreds, thousands, millions of such instances. Why would you want 
to name them all? What point of doing so is there? They have no need, and 
no benefit, to be given individual names. And consequent, when you ask 
the instance "What's your name?", they respond "I don't have one":

> # print(nt.__name__) # this would raise an AttributeError


However, when you ask the class ANamedTuple what its name it, it has a 
name, and can tell you:

> print(type(nt).__name__) # this is the desired output


If the instance nt claimed to be ANamedTuple, it would be *lying*. It 
isn't the class, and it shouldn't claim to have the same name as the 
class.


[...]
> As you can see, I snooped around in the object's type.  I found that the
> type, rather than the object itself, had the __name__ I was seeking.

Yes. And why do you consider this to be a problem?


> 1. WHY do only callable objects get a __name__?  A __name__ would seem
> to be a useful feature for other types.  Clearly, whoever implemented
> namedtuple thought it was useful to retain and display that information
> as a part of the string representation of the namedtuple (and I agree).

Because the namedtuple that you create *is* a class. (Type and class are, 
to a first approximation, synonyms.) Sadly, when you create a class using 
function-call syntax rather than the class keyword, you have to manually 
specify the name twice:

SomeTuple = namedtuple("SomeTuple", ...)


but that makes sense when you consider that Python has two concepts of 
names. The first SomeTuple, on the left of the equals sign, is the 
variable name. The second, inside the parentheses, is the class name. 
They need not be the same.


> 2. If I created a superclass of namedtuple which exposed
> type(namedtuple).__name__ in the namespace of the namedtuple itself,
> would I be doing anything harmful?

Harmful? No, except perhaps helping muddy the waters between classes 
(which have names) and instances (which generally don't). But why would 
you bother? The right way to handle this is, when you want the name of 
the type, ask for the name of the type:

type(instance).__name__



-- 
Steven



More information about the Python-list mailing list