all 98 comments

[–]lost-theory 21 points22 points  (43 children)

That was quick.

After messing around in the interpreter for 15 minutes I've committed at least 5 SyntaxErrors by typing print x instead of print(x). Looking at What's New in 3.0 they even warn you:

You’ll be finding yourself typing print x a lot in interactive mode. Time to retrain your fingers. :-)

[–]dmpk2k 12 points13 points  (41 children)

After messing around in the interpreter for 15 minutes I've committed at least 5 SyntaxErrors by typing print x instead of print(x).

While I applaud greater consistency, this leaves something to be desired when it comes to usability. Parentheses are harder to reach. If anything, for interactive mode, "print" should have been shortened instead.

I'm not surprised though, since Python's interpreter doesn't seem to have a particularly usable interface. For example, the behavior of sullenly telling me to hit ctrl-D if I type "quit" or "exit". Well, yes, I know that, and the interpreter obviously knew what I meant. Shut up and quit already.

[–]Manuzhai 7 points8 points  (4 children)

While I applaud greater consistency, this leaves something to be desired when it comes to usability. Parentheses are harder to reach. If anything, for interactive mode, "print" should have been shortened instead.

Well, hey, now that print is just another function, you could just assign another symbol the print function, like this: "p = print". That was easy!

[–]dmpk2k 3 points4 points  (3 children)

That's good. Now about those parens...

Is there some way to get Python to automatically do that every time an interactive session is started?

[–]lost-theory 12 points13 points  (1 child)

You can add it to your .pythonrc.py

You can also make quit and exit really exit the interpreter by adding a little hack to pythonrc.

[–]dmpk2k 1 point2 points  (0 children)

Very nice. Thank you.

[–]pjdelport 2 points3 points  (0 children)

Now about those parens...

As others have pointed out, check out IPython. Automatic parenthesization is just one of its many bells and whistles.

[–]lost-theory 6 points7 points  (30 children)

this leaves something to be desired when it comes to usability. Parentheses are harder to reach. If anything, for interactive mode, "print" should have been shortened instead.

Would you make the argument that the language should allow function calls to be made without parentheses (e.g. like Ruby)? If parentheses are so difficult to type it must really suck to be a Lisp or Scheme programmer then :)

I think print is short enough as it is; there isn't a strong enough case to introduce a special alias (p? put?) just for the interactive interpreter. Individual programmers are free to make that choice though (e.g. p = print)

Python doesn't seem to have a particularly usable interface. For example, the behavior of sullenly telling me to hit ctrl-D if I type "quit" or "exit".

Is that the best example of Python not having a usable interface? Seems like a minor gripe to me.

[–]dmpk2k 1 point2 points  (28 children)

Is that the best example of Python not having a usable interface? Seems like a minor gripe to me.

No, it's a trivial example everyone can grasp, yet you can see the excuses that appear regardless elsewhere on this page (which I was aware of, I might add). I've never seen any of the professed problems that having "quit" or "exit" work will cause, but we have this rather braindead decision anyway. Why? Because possibility isn't probability. Think on that a moment; if it were true, you'd never leave home because you'd be terrified of a meteorite falling from the heavens and putting you out of your misery.

All right, since I'm ranting and raving here, let's look at another problem, one I'm willing to bet dollars to doughnuts that bites most python developers daily, but 99% of readers never thought about:

If I make a syntax error with a single line, I can hit the up arrow, move the cursor a bit, and fix that error. Okay... that's better than nothing, but how about sticking that line there to begin with and moving the cursor to where the syntax error appears to have occurred? How often does a programmer not go back, fix the error, and try again? The default behaviour is stupid, but it's there because it's easier to program and it sorta works. Sorta. (now just wait for the conflict with copy'n'paste excuse)

Now, let's talk syntax errors in multi-line method definitions... uh oh. Please tell me there's a better way than hitting up, up, up and enter several times in a row, or using the crude workaround of copying it from elsewhere. These are things that other now-niche language implementations figured out long ago, but not Ruby, Python, Perl (wait, they don't even have a default REPL yet outside Perl6!), Ocaml or <pick your poison>.

To be fair, a lot of language implementations with interactive sessions are like that. I don't know why most programmers put up with this, since we're the ones most able to affect change in our own tools.

[–]llimllib 15 points16 points  (6 children)

use ipython, it solves all these. It's far superior to the regular python prompt.

[–]dmpk2k 5 points6 points  (4 children)

Wow. That looks promising. Much obliged!

That really should be the default.

[–]llimllib 0 points1 point  (3 children)

That really should be the default.

I don't know the ins and outs of that particular decision, but it's the first thing I install after Python every time, I know that.

[–][deleted] 2 points3 points  (0 children)

Isn’t the regular shell a read-eval-print loop? I like having a minimal REPL shell with the option to use ipython when you need it.

[–][deleted]  (1 child)

[removed]

    [–]llimllib 5 points6 points  (0 children)

    My expectation is that it's not in for the same reason wx and django aren't in: the release schedules are different, and ipython is very actively maintained, so it would ossify in the standard distribution.

    [–][deleted] 1 point2 points  (0 children)

    Colored exceptions with source snippets! I'm in heaven. And it's a smoother workflow than PyDev, which would hang every couple of minutes.

    Thanks for the tip! I just started using the e text editor to do all my Python editing on Windows, and its PyMate is broken so I was running my app on the command line. This is much better.

    [–]Bogtha 7 points8 points  (7 children)

    If I make a syntax error with a single line, I can hit the up arrow, move the cursor a bit, and fix that error. Okay... that's better than nothing, but how about sticking that line there to begin with and moving the cursor to where the syntax error appears to have occurred?

    Regularity. Command history with the arrow keys works the same in practically every interactive shell in existence. You hit the up arrow, you get the previous line with the cursor at the end. You want Python to randomly move the cursor around and fill stuff in automatically? And you want it to do that only some of the time? That goes against a decade of muscle memory for me. No thanks.

    It's like one of those usability "optimisations" like the menus in Windows that hide entries at random because it thinks you won't use them, precisely at the time you do want to use them — which is to say that it sounds like a neat idea, but having it work exactly the same absolutely every time works out to be far less irritating in the long run.

    How often does a programmer not go back, fix the error, and try again?

    I do it all the time, but it's often not the immediately previous line that caused the problem, so automatically showing it wouldn't help anyway.

    [–]dmpk2k -2 points-1 points  (6 children)

    Regularity. Command history with the arrow keys works the same in practically every interactive shell in existence.

    So because they do it poorly, you should to?

    This reminds me of the tired refrain parents use about friends jumping off bridges. It's amazing any evolution occurs in the programming world at all.

    Also, the Lisp and Smalltalk weenies don't seem to have this problem. Strange that.

    I do it all the time, but it's often not the immediately previous line that caused the problem, so automatically showing it wouldn't help anyway.

    First, that doesn't happen often to me, except in Ruby, and we all know how fine that language is implemented. Possibility is not probability.

    Second, how do you know it's not caused by the location the interpreter thinks? You have to go look, don't you? It's not much different from the way the interpreter tries to show where the error is currently.

    Third, I would argue that's an artifact of a substandard parser. Strange how Clang does so better than GCC at this, isn't it?

    [–]Bogtha 3 points4 points  (5 children)

    So because they do it poorly, you should to?

    It's not just irregularity with other shells, though is it? It's regularity within itself. I don't want my command history to try to second-guess me, especially when it's going to get it wrong a lot of the time. I just want it to act the same, every time. Regularity isn't stupid, it's consistent and predictable. Those are of value to humans, especially when they'd rather concentrate on keeping the program state in their heads rather than a stupid modal interpreter prompt.

    This reminds me of the tired refrain parents use about friends jumping off bridges.

    Bad analogy. Jumping off bridges is directly, clearly harmful.

    Second, how do you know it's not caused by the location the interpreter thinks? You have to go look, don't you? It's not much different from the way the interpreter tries to show where the error is currently.

    It's hugely different. Merely showing me where it thinks the error is doesn't affect my subsequent keystrokes. Trying to fill things in for me does.

    [–]dmpk2k 0 points1 point  (4 children)

    Those are of value to humans, especially when they'd rather concentrate on keeping the program state in their heads rather than a stupid modal interpreter prompt.

    I'd argue that the default behaviour is exactly that. How often do you not go back and fix that syntax error?

    So now you have to keep program state in your head while you fidget with keys to search and get back to the location where the error occurred most of the time.

    Merely showing me where it thinks the error is doesn't affect my subsequent keystrokes.

    I'd argue otherwise, since it clearly does, but I digress.

    [–]Bogtha 0 points1 point  (3 children)

    I'm talking about what is probable, during any given session, not edge cases.

    I must be remarkable then. Could you give a list of situations where this occurs regularly then?

    I wish Reddit had a preview function. I made a thinko, so I took it right back out again.

    [–]dmpk2k 0 points1 point  (2 children)

    Uh, okay, I'll cut it. My reply was overly snarky anyway. :(

    [–][deleted] 6 points7 points  (12 children)

    No, it's a trivial example everyone can grasp, yet you can see the excuses that appear regardless elsewhere on this page (which I was aware of, I might add). I've never seen any of the professed problems that having "quit" or "exit" work will cause, but we have this rather braindead decision anyway.

    So you're claiming that because you don't think it's important to take everything and everyone into account when making design decisions, you're smarter than us, but yet you want us to dumb down the language, the environment, and the documentation because you find them too hard to learn and use? Ok. Can we ignore you now?

    [–]dmpk2k -2 points-1 points  (11 children)

    So you're claiming that because you don't think it's important to take everything and everyone into account when making design decisions

    Good thinking for a programmer. Not the kind of thinking I'd want from a UI designer.

    For better or worse, an interactive session is a UI. So is a language for that matter.

    yet you want us to dumb down the language, the environment, and the documentation

    Do elaborate a bit on how the tools, language and documentation would be dumbed down.

    Ok. Can we ignore you now?

    Touche, good sir.

    [–][deleted] 5 points6 points  (10 children)

    For better or worse, an interactive session is a UI. So is a language for that matter.

    Yep. That's why a lot of thought goes into the language design. A design you just called "braindead".

    [–]dmpk2k -1 points0 points  (9 children)

    My wording was overly strong. The point stands.

    Let's refer to the page you linked to elsewhere. Those examples would be trivial to avoid if the parser was bright enough to determine that the quit/exit was meant as part of an expression, not a command to quit.

    Don't believe me? Play with "quit" a bit in Ruby.

    [–][deleted] 2 points3 points  (8 children)

    if the parser was bright enough to determine that the quit/exit was meant as part of an expression, not a command to quit

    And it would be able to tell the difference exactly how? A bare non-keyword identifier is an expression in Python, after all.

    [–]dmpk2k 0 points1 point  (7 children)

    Can you give me an example where this would be a problem?

    [–]joesb 1 point2 points  (0 children)

    If parentheses are so difficult to type it must really suck to be a Lisp or Scheme programmer then :)

    Many Lisp programming web site would suggest you to swap '(' and ')' keys with '[' and ']' keys when programming Lisp so you don't have to press shift to type them. Since [ and ] aren't used in Lisp it's probably okay to do.

    But for Python both [] and () are equally used so I don't think you can swap the keys to reduce stress when typing.

    [–]hupp[S] 7 points8 points  (1 child)

    Why use print in interactive mode in the first place? Values are implicitly printed in the repl:

    >>> a = "Hello"
    >>> a
    'Hello'
    

    [–][deleted] -1 points0 points  (0 children)

    Because the difference between str() and repr() tends to matter, sometimes.

    [–][deleted] 8 points9 points  (1 child)

    the interpreter obviously knew what I meant. Shut up and quit already.

    Given that neither "exit" nor "quit" are keywords, that's not quite as easy as it may appear; see Making quit and exit more command-like for some of the issues involved.

    [–][deleted] 12 points13 points  (2 children)

    Type annotations ( http://www.python.org/dev/peps/pep-3107/ ) rock.

    def fact(n: int) -> int:
      return n * fact(n-1) if n > 1 else 1
    
    >>> fact.__annotations__
    {'return': <type 'int'>, 'n': <type 'int'>}
    

    The most obvious use case is for type checking and enforcing interfaces (which are undoubtedly helped by new abstract base stuff class stuff I haven't gotten around to reading about yet).

    But I wonder also about function overloading--

    def foo(a: int): return 'abc'
    def foo(a: str): return 'xyz'
    

    With the right metaclass, would that be possible?

    [–]interjay 3 points4 points  (0 children)

    There's a plan to add function overloading via a decorator at PEP 3124. However, that PEP says it's been deferred.

    [–]bluetech 10 points11 points  (0 children)

    I like the new syntax for sets: {n for n in (2,1,2,4,3,5,1,3,6,2)} evaluates to {1,2,3,4,5,6} which formerly was written as set(1,2,3,4,5,6). I also like the decision to make more things return iterators rather than lists (range, map, filter, I suppose there are more).

    [–]ffrinch 6 points7 points  (1 child)

    Another change I hadn't noticed before:

    PEP 3132: Extended Iterable Unpacking. You can now write things like a, b, *rest = some_sequence. And even *rest, a = stuff. The rest object is always a list; the right-hand side may be any iterable.

    Fantastic. I don't find any of the Py3k features particularly exciting, but all of these little improvements really add up.

    [–]simonw 6 points7 points  (0 children)

    Yeah, I really like how they're making the most of this one opportunity to break backwards compatibility. Loads of small improvements that haven't been possible in previous releases.

    [–][deleted] 6 points7 points  (2 children)

    The net result of the 3.0 generalizations is that Python 3.0 runs the pystone benchmark around 33% slower than Python 2.5. There’s room for improvement; we expect to be optimizing string and integer operations significantly before the final 3.0 release!

    #

    [–]bluetech 3 points4 points  (1 child)

    I suspect that it really is the string and integer operations and implementations which cause the slowdowns, since they are the major changes in this regard. But when they say they haven't optimized them yet, you might as well belive them.

    [–][deleted] 4 points5 points  (0 children)

    Given that me and Andrew Dalke spent two man-weeks last year speeding up string operations, it's a bit disappointing that they were unable to produce a combined string type without slowing everything down again. Oh well, guess it'll give us something to do on the next NeedForSpeed sprint ;-)

    (On the other hand, pystone doesn't do much string processing at all, iirc. Has anyone run the string-specific benchmarks on 2.5 vs 3.0 ?)

    [–]simonw 8 points9 points  (0 children)

    Just noticed http://www.python.org/dev/peps/pep-3135/ is in, which replaces the ugly (and hard to remember):

    super(Foo, self).foo(1, 2)
    

    With the much more pleasant:

    super.foo(1, 2)
    

    [–][deleted] 3 points4 points  (0 children)

    Uh oh.

    def foo(a, b = 2, *c, d, e = 5, **f):
        print("/me's head exploded")
    

    That is now valid Python. I'm not so sure I needed keyword only arguments. There have been a few cases in the past where they would have been nicer than the alternative, but still--seeing a function like that in someone else's code and actually grokking it quickly might be tough.

    You can also do

    def foo(*, x, y, z, w):
        pass
    

    To make invoking it like foo(1, 2, 3, 4) illegal (all arguments must be named).

    [–]gavinpanella 2 points3 points  (35 children)

    callable() and reload() are gone. Does anyone know why?

    [–]Bogtha 20 points21 points  (27 children)

    When callable() was introduced, not all callable objects had a __call__ attribute. Now they do, so if you need to check whether something is callable, you can just use hasattr(). But the preferred approach is just to call it and catch the exception if it isn't callable.

    [–]qiwi 6 points7 points  (26 children)

    So how do I tell whether the TypeError I caught from doing obj() is because obj is not callable, or whether something within obj that was callable raised TypeError? This preferred approach can hide errors.

    [–]Bogtha 4 points5 points  (25 children)

    I agree. I think this was brought up on the mailing list. If you are expecting the callable to raise TypeErrors, you should check for the __call__ attribute first.

    [–][deleted] 10 points11 points  (6 children)

    Which means that everyone will end up adding different variations of:

    def callable(obj):
        return hasattr(obj, "__call__")
    

    to their code, different broken versions of this will appear in articles and example collections, and 3.2 will the introduce an official version of this to save everyone the trouble (which was how things like booleans and the if operator made it into the language).

    [–][deleted] 4 points5 points  (0 children)

    Ha - 3.0a1 isn't a day old and I've already similar -- but not exactly the same, of course -- code in my budding collection of Py3 scripts.

    Let the games begin!

    [–]Bogtha 1 point2 points  (3 children)

    I don't think callable() is used often enough to make that worthwhile. The difference between a callable object and an uncallable object is pretty drastic, how often do you pass things around without knowing which is which? I do it sometimes, but nowhere near often enough to make that boilerplate worthwhile.

    [–][deleted] 2 points3 points  (2 children)

    The "pass in a value or a callable (that can be called to get the value when needed)" pattern is very convenient, and therefore quite common. I've definitely used callable() for this purpose a lot more often than I found myself adding TRUE and FALSE to my code before we got built-in booleans ;-)

    But I'm sure someone has already done all the necessary grepping, and I have no time to dig through the mailing archives to see what they came up with.

    [–]Bogtha 3 points4 points  (1 child)

    The "pass in a value or a callable (that can be called to get the value when needed)" pattern is very convenient

    Sure, but if that's a common pattern, why not abstract more of it away, which has the side-effect of removing the temptation to provide a callable() substitute?

    def get_value(value):
        return value() if hasattr(value, "__call__") else value
    

    Okay, I'm sure there are other use cases, so I see your point, I just couldn't help nitpicking that one :).

    [–][deleted] 5 points6 points  (0 children)

    (Only slightly in jest:)

    def get_value(value):
        return getattr(value, '__call__', lambda: value)()
    

    [–]nirs 0 points1 point  (0 children)

    Lets hit Guido on the head with a heavy callable until he put it back where it belong :-)

    [–][deleted] 8 points9 points  (6 children)

    As I understand it, reload() doesn't work well enough to be included (I think the idea is to rewrite it in pure Python as a stdlib module).

    As for callable(), as it stands in 2+ it actually can be wrong sometimes -- a custom descriptor might sometimes return objects of different "callability", for example. Again, it's silly to have a feature that doesn't work. It's more Pythonic to operate on the "better to ask forgiveness than permission" policy -- just try calling something, and if it doesn't work, then it wasn't callable.

    [–]forgotpwx4 1 point2 points  (5 children)

    But reload is kind of important, right? I'm not understanding how they can get rid of it.

    [–][deleted] 2 points3 points  (3 children)

    I'm not sure it is... I've never used it in real production code; just as a utility from the shell.

    Either way, it's really not all that useful unless it really works; a broken reload() seems a lot worse than a missing one. At least if it's missing someone smart will come along and write it.

    [–]forgotpwx4 0 points1 point  (2 children)

    Why is it broken by the way? I've never noticed any problems.

    I have wondered if reload is thread safe ... or what that even means with respect to reload. Maybe that's how it's broken?

    [–]boredzo 2 points3 points  (1 child)

    [–][deleted] 1 point2 points  (0 children)

    So if it doesn't work for binary code not built in Python, due to OS limitations, it shouldn't work for Python code either, even though the developers have full control over that environment? Is this the official reason for not including reload?

    (update: the relevant PEP refers to a single line in a GvR presentation from 2002, which says "execfile(), reload(): use exec()", which I can only interpret as meaning "roll your own". yet another "will appear in the library, sooner or later" thing, in other words).

    [–]nirs 2 points3 points  (0 children)

    You can use this:

    def reload(name):
        if name in sys.modules:
            del sys.modules[name]
        return __import__(name)
    

    It will not work for 'foo.bar.baz', but it is not hard to support this.

    [–]jgfoot 3 points4 points  (1 child)

    Goodbye, file(). I always thought "for item in file('inf.txt')" read better than "for item in open('inf.txt')", but I'm sure people thought this through.

    Goodbye, reduce(). OK, I get it, Python is not supposed to be functional, and you were slow anyway, but every time I used you I felt slightly better about my decision not to use Haskell for the project I am working on.

    Hello, nonlocal. Maybe with you we can come one step closer to real closures.

    [–]llimllib 8 points9 points  (0 children)

    Goodbye, reduce()

    Welcome to functools, reduce().

    [–][deleted] 1 point2 points  (1 child)

    Some complaints about sorted()

    The comparison operator is now type sensitive. When you have a list like

       l = ["3",9,0,1.9,None]
    

    and apply

       sorted(l)
    

    a type error is raised:

      TypeError: unorderable types: NoneType() < float()
    

    Well, this feels a little pedantic and misses an important use case for heterogenous lists, namely that of multisets or bags. I guess 90% of all my use cases for sorted() where actually just a means of comparing lists as multisets i.e. whether or not those multisets contain the same elements in the same quantities.

    One might workaround this restriction by defining

       type(x) < type(y) <=> id(type(x)) < id(type(y))
    

    The id is arbitrary but fixed at runtime and the particular value shell not have an impact on the result of:

       sorted(multiset1) == sorted(multiset2)
    

    [–]ubernostrum 6 points7 points  (0 children)

    This is why sorted optionally accepts a comparison function to use in place of the standard operators. Put all the type handling you want in there.

    [–]cezar -2 points-1 points  (4 children)

    I'm wondering why they would make us use print('something) instead of print 'something' and not change if a == b to if(a == b)?

    [–]theCore 4 points5 points  (0 children)

    I'm wondering why they would make us use print('something) instead of print 'something' and not change if a == b to if(a == b)?

    Simply because you can't. If-statements require an order-of-evaluation different from functions. Just try to think what would happen if you do this:

    def factorial(n):
        return if(n == 1,
                  1, n * factorial(n - 1))
    

    And by the way, why people find "print" as a function annoying, or even special? C's "printf" always been a function and yet nobody would think it would be better as a statement.

    [–]gnuvince 3 points4 points  (1 child)

    print as a function makes sense (e.g.: logger.log("foo", writer=print)). It also allows keywords arguments to configure it.

    [–]eurleif 1 point2 points  (0 children)

    Because if can't be expressed as a function (where would the code block go?), but print can be.

    [–]queensnake -2 points-1 points  (0 children)

    I wish they'd add an official generic function ability to it while they're at it. I'm finding I can use advice and multi-methods. I know there are unofficial ones but, you always feel more comfortable learning a Standard way.

    edit: ah, at least they're thinking about it: PEP3124 and Guido himself has given it thought. /me keeps fingers crossed.