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 -- https://mail.python.org/mailman/listinfo/python-list