how to write function that returns function 
Author Message
 how to write function that returns function

I am not a python expert, and I'm hoping someone
can tell me how in Python to write a function
of one argument x that returns a function of one
argument y that returns x+y.

Here, in Scheme, is what I want to write:

(define foo (x) (lambda (y) (+ x y)))

I found on the web a page that says I could define
this as follows:

def addn(x):
  return lambda y,z=y: x+z

but I don't think this is exactly the same thing,
because it returns a function that takes a second
optional argument.  That is a substantial difference.
If the Scheme function is inadvertently called
(e.g. in someone else's code) with two arguments, it
would signal an error, whereas the code above would
quietly give the wrong answer.

I would appreciate it if someone could tell me the
standard way to write this so that it returns a
function of exactly one argument.

Thanks!





Sun, 31 Oct 2004 07:03:25 GMT  
 how to write function that returns function

Quote:

> I found on the web a page that says I could define
> this as follows:

> def addn(x):
>   return lambda y,z=y: x+z

> but I don't think this is exactly the same thing,
> because it returns a function that takes a second
> optional argument.  That is a substantial difference.
> If the Scheme function is inadvertently called
> (e.g. in someone else's code) with two arguments, it
> would signal an error, whereas the code above would
> quietly give the wrong answer.

This is the typical way of doing it, and yes, it is somewhat flawed.

In Python 2.1+ you can do:

from __future__ import nested_scopes

def addn(x):
    return lambda y: x+y

  Ian



Sun, 31 Oct 2004 07:10:26 GMT  
 how to write function that returns function

Quote:
>I am not a Python expert, and I'm hoping someone
>can tell me how in Python to write a function
>of one argument x that returns a function of one
>argument y that returns x+y.

>Here, in Scheme, is what I want to write:

>(define foo (x) (lambda (y) (+ x y)))

With nested scopes (default in 2.2, import nested_scopes from __future__ in 2.1),
you can do this:

 >>> def foo(x): return lambda y: x+y
 ...
 >>> f = foo(7)
 >>> f(3)
 10
 >>> import dis                             <-- handy disassembler for seeing what functions do etc.
 >>> dis.dis(f)
           0 SET_LINENO               1
           3 LOAD_DEREF               0 (x) <-- this loads the 7 from the closure
           6 LOAD_FAST                0 (y) <-- this loads the argument to the function
           9 BINARY_ADD
          10 RETURN_VALUE
 >>> f.func_closure
 (<cell at 0x008430C0: int object at 0x00795910>,)
 >>> hex(id(7))
 '0x795910'

Doing it as above captures x in a closure. I used a
small int 7 knowing the same instance would be used,
and we could recognize it in the closure by its id.

Quote:
>I found on the web a page that says I could define
>this as follows:

>def addn(x):
>  return lambda y,z=y: x+z

I don't think that's quite right. The idea is to capture x in
a way that works like the closure, and a dummy default value is
the mechanism, so I think it should be:

 >>> def foo(x): return lambda y,z=x: y+z
 ...
 >>> f = foo(7)
 >>> f(3)
 10
 >>> dis.dis(f)
           0 SET_LINENO               1
           3 LOAD_FAST                0 (y) <-- this loads the first function arg
           6 LOAD_FAST                1 (z) <-- this simulates the closure effect
           9 BINARY_ADD                         \_ unless you pass a second arg
          10 RETURN_VALUE
 >>> f.func_closure          <-- there isn't any (None)
 >>> f.func_defaults
 (7,)
 >>> f(3,5)       <-- the second arg overrides, so it's not a proper solution
 8

Quote:
>but I don't think this is exactly the same thing,
>because it returns a function that takes a second
>optional argument.  That is a substantial difference.
>If the Scheme function is inadvertently called
>(e.g. in someone else's code) with two arguments, it
>would signal an error, whereas the code above would
>quietly give the wrong answer.

right

Quote:
>I would appreciate it if someone could tell me the
>standard way to write this so that it returns a
>function of exactly one argument.

See above, but BTW, you don't have to use lambda at all:

 >>> def foo(x):
 ...     def forget_this_name(y):
 ...         return x+y
 ...     return forget_this_name
 ...
 >>> f = foo(7)
 >>> f(3)
 10
 >>> dis.dis(f)
           0 SET_LINENO               2

           3 SET_LINENO               3
           6 LOAD_DEREF               0 (x)  <-- this loads the 7 from the closure
           9 LOAD_FAST                0 (y)  <-- this loads the function arg
          12 BINARY_ADD
          13 RETURN_VALUE
          14 LOAD_CONST               0 (None) <--this is dead boilerplate code you don't get with lambda
          17 RETURN_VALUE
 >>> f.func_closure
 (<cell at 0x008430C0: int object at 0x00795910>,)  <-- proper closure this time. Note hex location
 >>> f.func_defaults                                <-- no defaults
 >>> f(3,5)                                         <-- strictly one arg, so this fails
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 TypeError: forget_this_name() takes exactly 1 argument (2 given)
 >>> hex(id(7))
 '0x795910'                                         <--hex location of 7

HTH

Regards,
Bengt Richter



Sun, 31 Oct 2004 09:37:23 GMT  
 how to write function that returns function

Quote:
> I am not a Python expert, and I'm hoping someone
> can tell me how in Python to write a function
> of one argument x that returns a function of one
> argument y that returns x+y.

> Here, in Scheme, is what I want to write:

> (define foo (x) (lambda (y) (+ x y)))

> I found on the web a page that says I could define
> this as follows:

> def addn(x):
>   return lambda y,z=y: x+z

> but I don't think this is exactly the same thing,
> because it returns a function that takes a second
> optional argument.  That is a substantial difference.
> If the Scheme function is inadvertently called
> (e.g. in someone else's code) with two arguments, it
> would signal an error, whereas the code above would
> quietly give the wrong answer.

> I would appreciate it if someone could tell me the
> standard way to write this so that it returns a
> function of exactly one argument.

There's no need to use lambda, and indeed I eschew it whenever it make sense
to do so. From 2.2 on you don't need top import nested_scopes from
__future__, by the way. Since functions are fisrt-class objects, it doesn't
matter what name is associated with the declarations - they can be bound to
any variable once they are returned.

Python 2.2 (#1, Dec 31 2001, 15:21:18)
[GCC 2.95.3-5 (cygwin special)] on cygwin
Type "help", "copyright", "credits" or "license" for more information.

Quote:
>>> def adder(x):

...     def anyoldname(y):
...         return x+y
...     return anyoldname
...

Quote:
>>> add3 = adder(3)
>>> add100 = adder(100)
>>> add3(12)
15
>>> add100(12)
112

Note, however, that the function name (the name bound to it in the def
statement) does get built in to its repr():

Quote:
>>> add3

<function anyoldname at 0x100fffe8>
Quote:
>>> add100

<function anyoldname at 0x10100278>

Hope this helps.

regards
 Steve
--
-----------------------------------------------------------------------
Steve Holden                                 http://www.holdenweb.com/
Python Web Programming                http://pydish.holdenweb.com/pwp/
-----------------------------------------------------------------------



Sun, 31 Oct 2004 10:28:43 GMT  
 how to write function that returns function

Quote:
>I am not a Python expert, and I'm hoping someone
>can tell me how in Python to write a function
>of one argument x that returns a function of one
>argument y that returns x+y.

>Here, in Scheme, is what I want to write:

>(define foo (x) (lambda (y) (+ x y)))

>I found on the web a page that says I could define
>this as follows:

>def addn(x):
>  return lambda y,z=y: x+z

Get a recent version of Python that includes 'nested scopes' a la Lisp, and
try:

Quote:
>>> from __future__ import nested_scopes  # Turn on nested scopes
>>> def f(x):

        def g(y):
                return y +x
        return g

Quote:
>>> adder = f(3)
>>> adder(4)

7

BTW, this is not exactly the same behavior you find in Lisp. For example:

x = 0 #Global variable
def f():
  x = 3  # Doesnt create a dynamic binding, it creates a new local variable
  return x

The 'x = 3' doesn't "setf", it "let"s

I find this behavior disturbing, and I hope special variables in Arc will
behave as in Common Lisp.

Good luck with Arc! :-)

-----------------------
Fernando Rodriguez



Sun, 31 Oct 2004 15:21:46 GMT  
 how to write function that returns function
Thanks to everyone who replied to my earlier question.  It seems
Python scope rules have changed recently, and my info was out of
date.  I am still uncertain about a couple things though: there
seem to be some restrictions on what you can do with lexical
variables and also what you can put in a lambda.  Can some Python
expert tell me how you would express the Common Lisp

(defun foo (n) #'(lambda () (incf n)))

in Python?

Many thanks,  --pg



Mon, 01 Nov 2004 00:15:53 GMT  
 how to write function that returns function

Quote:

> Thanks to everyone who replied to my earlier question.  It seems
> Python scope rules have changed recently, and my info was out of
> date.  I am still uncertain about a couple things though: there
> seem to be some restrictions on what you can do with lexical
> variables and also what you can put in a lambda.  Can some Python
> expert tell me how you would express the Common Lisp

> (defun foo (n) #'(lambda () (incf n)))

> in Python?

You can't directly translate that.  Access to variable of enclosing
scopes is read only (except in the case of global statements, but that
doesn't help here).

The usual response to questions like this is "what is it you're
actually trying to *do*?"; there may well be a natural way of
acheiving *that* despite the fact that there are no non-horrible
direct translations of the above code (usually involving defining a
class or two...).

Cheers,
M.

--
  It's a measure of how much I love Python that I moved to VA, where
  if things don't work out Guido will buy a plantation and put us to
  work harvesting peanuts instead.     -- Tim Peters, comp.lang.python



Mon, 01 Nov 2004 00:34:08 GMT  
 how to write function that returns function

Quote:

> Thanks to everyone who replied to my earlier question.  It seems
> Python scope rules have changed recently, and my info was out of
> date.  I am still uncertain about a couple things though: there
> seem to be some restrictions on what you can do with lexical
> variables and also what you can put in a lambda.  Can some Python
> expert tell me how you would express the Common Lisp

> (defun foo (n) #'(lambda () (incf n)))

> in Python?

> Many thanks,  --pg

Here's one way:

class foo:
  def __init__(self, n):
    self.n = n

  def next(self):
    self.n += 1
    return self.n

def mkfoo(n):
  f = foo(n)
  return f.next

bar = foo(1)

print bar(), bar(), bar()
-> 2 3 4

I don't think that the "Guido implementation" of Python allows the
capture of state in closures the same way that you can in Scheme and
CL, though you can fake it very easily, as above.

G



Mon, 01 Nov 2004 01:38:26 GMT  
 how to write function that returns function
Correction:

Quote:


> > Thanks to everyone who replied to my earlier question.  It seems
> > Python scope rules have changed recently, and my info was out of
> > date.  I am still uncertain about a couple things though: there
> > seem to be some restrictions on what you can do with lexical
> > variables and also what you can put in a lambda.  Can some Python
> > expert tell me how you would express the Common Lisp

> > (defun foo (n) #'(lambda () (incf n)))

> > in Python?

> > Many thanks,  --pg

> Here's one way:

> class foo:
>   def __init__(self, n):
>     self.n = n

>   def next(self):
>     self.n += 1
>     return self.n

> def mkfoo(n):
>   f = foo(n)
>   return f.next

> bar = foo(1)

bar = mkfoo(1)

Quote:
> print bar(), bar(), bar()
> -> 2 3 4

G


Mon, 01 Nov 2004 01:49:06 GMT  
 how to write function that returns function
Playing around a bit...

CL:

(defun foo (n) #'(lambda () (incf n)))

Python:

def foo(n=0):
  class bar:
    def __init__(self):
      self.n = n
    def next(self):
      self.n += 1
      return self.n
  return bar().next

f = foo()
print f(),f(),f()
-> 2 3 4
g = foo(1)
-> 3 4 5

Arc: ? ;)

G



Mon, 01 Nov 2004 02:22:26 GMT  
 how to write function that returns function


Quote:
> CL:

> (defun foo (n) #'(lambda () (incf n)))

> Python:

> def foo(n=0):
>   class bar:
>     def __init__(self):
>       self.n = n
>     def next(self):
>       self.n += 1
>       return self.n
>   return bar().next

> f = foo()
> print f(),f(),f()
> -> 2 3 4
> g = foo(1)
> -> 3 4 5

You seem to have an off by one error on your output:
I get 1 2 3 and 2 3 4

Anyway, as long as you're going to do that, why not:

from __future__ import generators

def foo(n=0):
    def bar(n=n):
        while 1:
            n += 1
            yield n
    return bar().next

[ from earlier message by same author: ]

Quote:
> I don't think that the "Guido implementation" of Python allows the
> capture of state in closures the same way that you can in Scheme and
> CL, though you can fake it very easily, as above.

I think the key difference is that Python's closures only give you read
access to the variables.  If you want write access you have to
encapsulate them in something else, like a list:

def foo(n=0):
    n=[n]
    def bar():
        n[0] += 1
        return n[0]
    return bar

--
David Eppstein       UC Irvine Dept. of Information & Computer Science



Mon, 01 Nov 2004 02:44:44 GMT  
 how to write function that returns function
Quote:

> def addn(x):
>   return lambda y,z=y: x+z

(assuming you mean lambda y,z=x: x+z)

Quote:

> but I don't think this is exactly the same thing,
> because it returns a function that takes a second
> optional argument.  That is a substantial difference.

This is embarrassing, which I guess is why we have nested scopes in
2.1+ so we don't have to do this any more; but here's a solution for
1.5.2:

class addn:
    def __init__(self, x): self.x = x
    def __call__(self, y): return self.x + y

This is a class instead of a function, but that is not a substantial
difference.

Unlike the nested-scopes case, this lets you modify the state of the
object in a straightforward way; a "counter" closure in Python is
ugly:

def counter(startvalue):
    state = [startvalue]
    def counter_internal():
        state[0] += 1
        return state[0]
    return counter_internal

The class equivalent is a little better:
class counter:
    def __init__(self, startvalue): self.state = startvalue
    def __call__(self):
        self.state = self.state + 1
        return self.state

(I didn't use += because this class version will work in 1.5.2 and
earlier Pythons, which don't have +=.  The nested-scopes version
doesn't.)



Mon, 01 Nov 2004 05:34:39 GMT  
 how to write function that returns function

Quote:
> You can't directly translate that.  Access to variable of enclosing
> scopes is read only (except in the case of global statements, but that
> doesn't help here).

It looks as if the closest thing would be something like this,
which a Python expert sent me:

def foo(n):
  s = [n]
  def bar(i):
    s[0] += i
    return s[0]
  return bar

Although you can't modify variables from outer scopes, you can
modify *parts* of them (which to me seems like the same thing...)

The reason this problem seems kind of artificial is that I don't
need to solve this actual problem.  I heard that recent Python
versions had added more support for lexical closures, and was
curious how well Python works for the type of programming in
Structure and Interpretation of Computer Programs; this is kind
of a hello_world of that genre.  (It's not a homework problem,
I swear.)

Incidentally, here is Perl 5 code someone sent me for this case:

sub foo {

  return sub {return $n += $_[0]}}

--pg



Mon, 01 Nov 2004 07:04:05 GMT  
 
 [ 29 post ]  Go to page: [1] [2]

 Relevant Pages 

1. how to write function that returns function

2. function that returns function

3. F95: array-returning function as argument to another function

4. about functions that return functions.

5. question about writing to the return value of a system function using vpi_put_value()

6. VC++ calling fortran function and fortran function calling a c++ function

7. Calling functions from functions from functions ...

8. returning ARRAY structures from DLL-functions in Dyalog

9. returning values through functions calls

10. return multiple values from an awk function?

11. return more than one parameter from a function

12. returning values from a function in a shell script

 

 
Powered by phpBB® Forum Software