Hacker News new | past | comments | ask | show | jobs | submit login

I have only a trivial amount of experience experience with Scheme, could you explain how its closures are different from Python's?

I haven't used Java a lot either, but from what I have done Python's function seems more similar to JavaScript than to Java.




> I have only a trivial amount of experience experience with Scheme, could you explain how its closures are different from Python's?

In pre Python 3, the closed over value isn't mutable unless it's a reference to a mutable object.

        def counter(num):
            def foo():
                num += 1
                return num
            return foo

    c = counter(5)
    c()
This won't work because you can't mutate the closed variable `start`.

This would work in languages with proper closures(Ruby, Perl, Scheme...).

Here is how you do it in Ruby:

    def counter(n)
        lambda { n += 1 }
    end
    c = counter(5)
    c[] # returns 6
    c.call() # Alternate syntax. returns 7
    c[] # returns 8
The above python will work in Python 3 if the closed variable is declared `nonlocal`.

    def counter(num):
       def foo():
           nonlocal num
           num += 1
           return num
       return foo
Or you can have workarounds in pre Python3.

    def counter(num):
       def foo():
           foo.num += 1
           return foo.num
       foo.num = num
       return foo


I dunno if I'd say that's an issue of Python not having proper closures, or just that before you could say 'nonlocal' there was no way to refer to the outer scope, since the only scopes you could refer to were 'local' and 'global'.


Python has had proper closures since version 2.2, which is quite old at this point. You can verify this using the following code:

    def func():
        x = []
        def func2():
            x.append(1)
            return x
        return func2
    closed = func(); closed(); assert closed() == [1,1]
    closed = func(); closed(); assert closed() == [1,1]


That's what I was referring to as "Java closures".


In Perl, for reference:

  use strict; use warnings;

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

  my $c = counter( 5 );
  say $c->();
  say $c->();


And its also handy that you can create a closure without needing to define a subroutine:

  my $c = do {
      my $n = 5;
      sub { ++$n }
  };


[deleted]


> In pre Python 3, the closed over value isn't mutable unless it's a reference to a mutable object. > Proper closures were added in Python 2.2 (which is quite old at this point), not Python 3.

x is a reference to a mutable object(list), and it's not x which is mutated but what x refers to. Pre python 3 doesn't have proper closures - ways to emulate it, yes. Proper closures - no.


Python closes over names, not objects. This is consistent with the rest of Python, which treats names as references to objects rather than variables which hold objects. I do agree that it's confusing for people used to closures and used to languages with different semantics.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: