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 Spam Spam'
But now watch what happens when we create a new function with the name
spam. It hijacks the recursive call:
.... return "ham-like meat product"
....'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:
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:
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.