Mailing List Archive


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tlug] "Assignment" "Expressions"



Curt Sampson writes:

 > Which pure functional languages have assignment expressions,

YHBT.  OK, "slightly" impure: I was thinking of setq.  There's
probably a better way to describe Lisp (starting with a four-letter
word, no, not that one, nor that one, I mean L-I-S-P).

 > >     (The answer is NOT "Python
 > >     doesn't have an assignment expression yet".)
 >
 > Well, technically, Python doesn't have an "assignment operator" that
 > does only that.  (I'm always scratching my head over whether `=` is
 > doing binding or assignment.[1])

It's binding.  It can't be assignment because there's no there there
to be assigned to.

 > [1]: http://ashtonkemerling.com/blog/2013/04/30/binding-vs-assignment/

Author didn't understand function scope in Python.

Function definitions do not create closures in the way you might
expect.  Variables are local if bound in the function before access
(this may shadow bindings of the same name in enclosing scopes), else
local to parent function if declared nonlocal (Python 3 only), else
(module-) global.  In the "nonlocal" and "global" cases, if not bound
when that access is executed in a call to that function, a NameError
will be signaled (in fact in the nonlocal case the error is often
detected at compile time as a SyntaxError).

So what is described in that blog is simply the fact that the i being
printed is evaluated at function call time, not at function definition
time.  The behavior is well-defined, correctly explained in the
language reference and tutorial, and I find it intuitive (but then
again, perhaps I was perverted by the use, not merely of a four-letter
word, but of a variant favored by RMS).

There's a well-known idiom for doing what the colleague wanted to do:

    funs = []
    for i in ["a", "b"]:
        def _(i=i):        # LOOK MA!  THIS IS IT!
            print (i)
        funs.append(_)
    funs[0]()
    funs[1]()

This idiom is *also* a newb-chomping Venus flytrap.  In the variable's
default initialization, the "i" on the RHS is dereferenced to an object
at function definition time.  For nonmutable objects, no problem, but
for a mutable initializer, such as "[]", the *same* object is used in
all invocations of the function.  This often surprises newbs who write
functions like

    def list_squares_to(n, l=[]):
        for i in range(n):
            l.append(i*i)
        return l

Go ahead, call that twice with n > 0, I dare you:

    list_squares(1)
    list_squares(1)



Home | Main Index | Thread Index

Home Page Mailing List Linux and Japan TLUG Members Links