On Sun, 23 Mar 2008 13:51:34 -0400, Roy Smith wrote: > On the other hand, when I do: > > def torture(): > woman.putInChair() > cushion.poke() > rack.turn() > > I've also done two things. First, I've created a function object (i.e. > a lambda body), and I've also bound the name torture to that function > object, in much the same way I did with the list. But, it's different. > The function object KNOWS that it's name is torture.
No it does not. Function objects don't know their name. All they know is that they have a label attached to them that is useful to use as a name in some contexts, e.g. when printing tracebacks. It's just a label, nothing more. You can prove that for yourself with a few simple tests. Firstly, we can prove that functions don't know what they are called by writing a recursive function: def spam(n): if n <= 1: return "Spam" return "Spam " + spam(n-1) If spam() knows what it is called, then you should be able to rename the function and the recursive call will continue to work. But in fact, that's not what happens: >>> spam(3) # check that it works 'Spam Spam Spam' >>> tasty_stuff = spam # make an alias >>> tasty_stuff(3) 'Spam Spam Spam' But now watch what happens when we create a new function with the name spam. It hijacks the recursive call: >>> def spam(n): ... return "ham-like meat product" ... >>> tasty_stuff(3) 'Spam ham-like meat product' The function formerly known as "spam" isn't calling itself, it is merely calling a function by name "spam". But we can see that the function tasty_stuff() is still using the old "spam" label for itself: >>> tasty_stuff('foo') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in spam TypeError: unsupported operand type(s) for -: 'str' and 'int' Unfortunately there's nothing we can do to fix that error. Even though the function object has an attribute "__name__" (also known as "func_name") which is set to spam, it isn't used for tracebacks. Instead, the label comes from a read-only attribute buried deep in the function object: >>> tasty_stuff.func_code.co_name = 'yummy meat-like product in a can' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: readonly attribute This is a mistake, in my opinion. It's an arbitrary decision to make this read-only (as far as I can tell), which goes against the grain of Python's "we're all consenting adults here" philosophy. By the way, in case you're thinking that wanting to change the (so- called) name of a function is a silly think to do, not at all. Consider factory functions: def factory(how_much): def f(n=1): for i in range(n): print "I love spam a %s" % how_much return f Every function created by the factory has the same "name", no matter what name you actually use to refer to it. factory('little') and factory('lot') both uselessly identify themselves as "f" in tracebacks. The truth is that objects don't know what name they have, because objects don't have names. The relationship is the other way around: names have objects, not vice versa. Some objects (functions, classes, anything else?) usefully need a label so that they can refer to themselves in tracebacks and similar, and we call that label "the name", but it's just a label. It doesn't mean anything. [snip] > What Python give us with lambdas is some half-way thing. It's not a > full function, so it's something that people use rarely, Which people? > which means most people (like me) can't remember the exact syntax. Speak for yourself, not for "most people". > Even when I know > it's the right thing to be using in a situation, I tend not to use it > simply because the path of least resistance is to write a one-off > function vs. looking up the exact syntax for a lambda in the manual. lambda arguments : expression Why is that harder to remember than this? def name ( arguments ) : block And don't forget to include a return statement, or you'll be surprised by the result of the function. -- Steven -- http://mail.python.org/mailman/listinfo/python-list