Live data from Hacker News

Python and the Principle of Least Astonishment

lucumr.pocoo.org

11–20 of 53 posts

Re: Python and the Principle of Least Astonishment

#11
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 decorators.

Re: Python and the Principle of Least Astonishment

#12

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…

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

Re: Python and the Principle of Least Astonishment

#13
It's a bit dated, but the Python Cookbook does a great job of teaching you practical examples of Python if you already know other languages and want to quickly grok what is "pythonic." It starts with string crunching and hits just about every other general sysadmin use case, covering most of the standard library along the way.

Re: Python and the Principle of Least Astonishment

#14
post #9

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…

Python has Java like closures? No comprende.

Java's closures are a pain as they need inner classes to emulate closures - Python's are a lot easier, hands down.

Java needs the local variables to be final for it to close over them. Python doesn't but you can't directly mutate it. Won't you agree in that sense the statement holds some truth?

Re: Python and the Principle of Least Astonishment

#15

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…

> I think he may not understand them.

I won't think so. He codes a lot, in general, and in Python. I have read some of his posts and code, and he has a deep understanding of Python and programming in general.

His complain was about @foo and @foo() requires different decorator implementations. If @foo by default meant @foo(), that makes introducing parameters at a later time a bit more straightforward.

I am not arguing about it being a valid expectation. I am just explaining what I think he meant.

Re: Python and the Principle of Least Astonishment

#16

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…

> then I realized that Ruby isn't quite like them either.

I am curious. How does Ruby's closure differ from Scheme's?

Re: Python and the Principle of Least Astonishment

#17
post #10

For extra fun.... a = 5 def print_a(): print a # Prints 5 print_a() def print_and_assign_a(): print a a = 2 # raises UnboundLocalError print_and_assign_a() class PrintOnInitSet(set): def __init__(self, *args, **kwargs): print "init!" set.__init__(self, *args, **kwargs) # Creates a PrintOnInitSet and prints "init!" a = PrintOnInitSet([1,2]) # Creates a PrintOnInitSet and prints "init!" b = PrintOnInitSet([3,4]) # Crea…

Well, your first example makes sense. It ensures you're always referring to the same-scoped 'a' throughout your function. FWIW if you said 'global a' at the start of 'print_and_assign_a', Python wouldn't have a problem: >>> a = 5 >>> def print_and_assign_a(): ... global a ... print(a) ... a = 2 ... >>> print_and_assign_a() 5 >>> print_and_assign_a() 2 Your second example, however, seems to show an implementation deta…

The 'print_and_assign_a' case comes up more often with a in an enclosing local scope, so you couldn't really get it to work prior to the introduction of 'nonlocal' in Python 3. The best you could do was something silly like

  a = [5]
  def print_and_assign_a():
      print(a[0])
      a[0]=2
It's cool that the second case works in other implementations. I hadn't thought to test that.

Re: Python and the Principle of Least Astonishment

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

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

Re: Python and the Principle of Least Astonishment

#19
post #10

Earlier quoted context omitted.

Well, your first example makes sense. It ensures you're always referring to the same-scoped 'a' throughout your function. FWIW if you said 'global a' at the start of 'print_and_assign_a', Python wouldn't have a problem: >>> a = 5 >>> def print_and_assign_a(): ... global a ... print(a) ... a = 2 ... >>> print_and_assign_a() 5 >>> print_and_assign_a() 2 Your second example, however, seems to show an implementation deta…

The 'print_and_assign_a' case comes up more often with a in an enclosing local scope, so you couldn't really get it to work prior to the introduction of 'nonlocal' in Python 3. The best you could do was something silly like a = [5] def print_and_assign_a(): print(a[0]) a[0]=2 It's cool that the second case works in other implementations. I hadn't thought to test that.

Yes, 'nonlocal' definitely closed a hole in the language.

Re: Python and the Principle of Least Astonishment

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

[deleted]
Post reply on HN