Live data from Hacker News

Python and the Principle of Least Astonishment

lucumr.pocoo.org

21–30 of 53 posts

Re: Python and the Principle of Least Astonishment

#21
post #12

Earlier quoted context omitted.

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…

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]

Re: Python and the Principle of Least Astonishment

#22
post #20
post #12

Earlier quoted context omitted.

> 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…

[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.

Re: Python and the Principle of Least Astonishment

#23
post #12

Earlier quoted context omitted.

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…

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.

Re: Python and the Principle of Least Astonishment

#24

Overall it's a good article, but I don't fully understand his complaint about decorators, and I think he may not understand them. @foo and @foo() intentionally mean very different things. I don't see how you could "add a parameter to a previously parameter-less decorator" without drastically changing the meaning of the whole thing. They may be tricky to wrap your head around, but there's nothing too surprising about…

If I have the following code:

    @auth_required
    def some_view():
        pass
And later I decide to change that decorator to be parameterized:

    @auth_required("basic")
    def some_view():
        pass
I have now created a massive amount of pain for myself if I decide to define auth_required() such that it defaults its argument to "basic", unless I force people to call it as @auth_required(), because of the differing callable signatures.

Some people feel @auth_required() is ugly. That's all.

Re: Python and the Principle of Least Astonishment

#25

This is a nice article, as a non-Python programmer who's dabbled a bit in order to read some random Python code, it gave me some appreciation for the "Pythonic"-way. I have to say though, that the thing that astonished me the most about Python is the Java-like "closures". I sort of thought it would be like Ruby, which I thought was closer to Scheme and JavaScript, and then I realized that Ruby isn't quite like them e…

you should read Armin's other posts about Python and webdev, if you haven't already:

http://lucumr.pocoo.org/tags/python/

Re: Python and the Principle of Least Astonishment

#26
post #12

Earlier quoted context omitted.

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…

In Perl, for reference:

  use strict; use warnings;

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

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

Re: Python and the Principle of Least Astonishment

#27
post #12

Earlier quoted context omitted.

> 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…

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 }
  };

Re: Python and the Principle of Least Astonishment

#28

Overall it's a good article, but I don't fully understand his complaint about decorators, and I think he may not understand them. @foo and @foo() intentionally mean very different things. I don't see how you could "add a parameter to a previously parameter-less decorator" without drastically changing the meaning of the whole thing. They may be tricky to wrap your head around, but there's nothing too surprising about…

If I have the following code: @auth_required def some_view(): pass And later I decide to change that decorator to be parameterized: @auth_required("basic") def some_view(): pass I have now created a massive amount of pain for myself if I decide to define auth_required() such that it defaults its argument to "basic", unless I force people to call it as @auth_required(), because of the differing callable signatures. So…

> Some people feel @auth_required() is ugly. That's all.

The biggest issue here is backwards compatibility. Nowadays I just make a separate decorator that accepts arguments and keep the old one around unchanged. I learned my lesson :)

Re: Python and the Principle of Least Astonishment

#30

"I was quite fond of Raymond Hettinger's talk about what makes Python unique because he showed a bunch of small examples that almost exclusively used the good parts of the standard library and hardly any user written logic." Is this talk available anywhere?

I'm not certain but I think it was one of these

http://ep2011.europython.eu/conference/speakers/raymond-hett...

Post reply on HN