
New features you can't use unless you are in Python 3 - bkudria
http://www.asmeurer.com/python3-presentation/slides.html#1
======
KerrickStaley
One big thing that's missing from this list is the __traceback__ on
exceptions, which pretty much does what you think it does. In Python 2,
there's _no_ way to access the traceback for an exception once you've left the
`except:` block. This matters when you're using things like gevent; if one of
your gevent greenlets throws an exception and you inspect the .exception
attribute on it, you'll be able to get the exception message but won't know
what line it came from.

N.B. This is absent from Python 2 due to concerns with creating self-
referential loops. The garbage collector got better in the meantime and the
feature was never backported to Python 2.

~~~
jsmthrowaway
Huh, I was almost sure you were wrong and that I'd done this before, but the
frame does indeed "go away" once you leave the except block. Fascinating.

    
    
        In [8]: try: crasher()
           ...: except TypeError as e:
           ...:     exc = e
           ...:
    
        In [9]: type(exc)
        Out[9]: TypeError
    
        In [10]: traceback.print_tb(exc)
        AttributeError: 'exceptions.TypeError' object has no attribute 'tb_frame'
    

I can understand the concern, though it seems like there would be easier fixes
than the garbage collector for that specific case.

------
dlbucci
I did not know you could append to a Path via "/", but that's really awesome!
I also really love working with generators when I write Python. They are just
such a simple idea that's very powerful and I miss them so much when I go back
to javascript (I know javascript has them now, but I haven't written them, and
they don't look as fluent as Python 3, where the large parts of the language
design is based around them).

~~~
Animats
Overloading operators for cute purposes is usually a misfeature. There was a
fad for this in the early C++ days. I once wrote a marshalling library which
overloaded "||", so that you could write

    
    
        p = stream || rec.a || rec.b || rec.c;
    

and get an object which, if written, marshalled the record, and if read,
unmarshalled it. The marshalling order was only specified once. Cute, but in
retrospect, bad.

Python's classic overload problem comes from using "+" for concatenate. For
built-in vectors, "+" is concatenate, but for NumPy arrays, it's addition. You
can use "+" between a NumPy array and a built-in vector. Does it add, or
concatenate?

("|" is supposed to be the concatenate operator; it was added to ASCII to
support PL/I. But decades of C have made it the bitwise OR operator to most
programmers, so we're stuck. "_" is allowed within symbols, so that's taken.
There's "⁀", character tie, but nobody can type it.)

It seems to be best to restrict the math operators to math.

~~~
dragonwriter
> Overloading operators for cute purposes is usually a misfeature

Whether a function for which an operator is overloaded is “cute” or
“fundamental to clarity” depends on the context in which it is used.

> There was a fad for this in the early C++ days.

Yeah, like overloading the bitwise shift operators as stream
insertion/extraction operators.

> Python's classic overload problem comes from using "+" for concatenate. For
> built-in vectors, "+" is concatenate

Python doesn't have built-in vectors, it has lists.

> but for NumPy arrays, it's addition.

Not sure I see a problem. For numbers, it's an addition. For simple ordered
collections, it's concatenation. For matrix-like collections, it's memberwise
addition.

> You can use "+" between a NumPy array and a built-in vector. Does it add, or
> concatenate?

To the extent _that 's_ a problem, it's a problem with implicit coercion more
than operator overloading.

~~~
jacquesm
> Whether a function for which an operator is overloaded is “cute” or
> “fundamental to clarity” depends on the context in which it is used.

The fact that it requires context other than the language spec is where the
problem resides. The cognitive overhead of reading code is high enough without
having to alias common operators.

~~~
dragonwriter
> The cognitive overhead of reading code is high enough without having to
> alias common operators.

The cognitive overhead of reading code is, IME, often lower with context-
approprate operator overloading (just as it is with well-chosen vs. poorly-
chosen method names.)

There is a reason human languages (and, yes, even the notation of mathematics)
develops context-specific dialects, and it is to _reduce_ the cognitive
overhead of communication. Code switching with clear contextual boundaries is
often far more efficient than using a one-size-fits-all notation that is
context-insensitive.

~~~
Diederich
I'm pleased to see this perspective represented; it's the main reason I still
really love the Perl programming language. The idea that context is useful and
can actually help with clarity is a core concept.

~~~
ethbro
The problem is that a reasonable context response is different from person to
person and culture to culture.

I feel like this makes things like using operator overloading to clean up code
incredibly dangerous, especially in popular libraries.

Best: Context-appropriate overload that makes sense to me

Good: Standard language meaning that may not fit cleanly in context, but has
the same definition always

Worst: Context-appropriate overload that doesn't make sense to me

So if you aren't sure whether or not your clever idea will actually fall in
the third category for some people, go with the second instead of pushing for
the first.

Aka, "for every story someone can tell of a magical operator overloading that
makes code more readable, I can come up with some dumbass architect who did
the most counterintuitive thing you can imagine."

------
morinted
I really like the format strings in Python 3.6:
[https://docs.python.org/3/whatsnew/3.6.html#whatsnew36-pep49...](https://docs.python.org/3/whatsnew/3.6.html#whatsnew36-pep498)

Seems that this set of slides (which were very informative!) is for up to 3.5

~~~
lottin
How many format strings does Python have already?

~~~
baq
[https://pyformat.info/](https://pyformat.info/) should know, ask it

~~~
Sir_Cmpwn
This link does not mention f-strings, the feature in question.

The answer is there are 3 ways to format a string: %, .format, and f-strings.

~~~
deathanatos
.format() and format string literals essentially share the same syntax, so I
don't really think it's fair to bracket them out separately.

You could sort of pull a retcon and say that .format() is the dynamic form of
f'' literals.

Having used the equivalent feature in JavaScript, this stuff is super handy.
It also makes "printf" a lot nicer:

    
    
      print('I have {count} {color} {object}'.format(count=count, color=color, object=object))
      print('I have {} {} {}'.format(count, color, object))
      print(f'I have {count} {color} {object}')
    

% had real issues, so I'm quite glad .format() came along.

------
signet
My personal favorite is native support for IP addresses, introduced in python
3.3[0]. Makes IP math and address validation so much easier.

[0]
[https://docs.python.org/3/library/ipaddress.html](https://docs.python.org/3/library/ipaddress.html)

~~~
est
> address validation

just try: socket.inet_aton

~~~
pwdisswordfish
That doesn't seem to support IPv6 at all. And doesn't let you do much with a
parsed address either.

------
NuSkooler
How old is Python 3 now? I've always used Python for a "miscellaneous task"
language, and still do... and even I find "...because you refuse to upgrade" a
bit insulting. If I used it for something serious, even more so.

The way 2.x -> 3.x was handled is/was/will is an absolute disaster. Upgrading
simple scripts is a non-issue. Larger projects seem to always be a horrible
pain.

~~~
huskyr
I used to think like you, but when i started actually using Python 3 it all
was a lot less worse than i've expected it to be from reading Hacker News
comments. YMMV, but converting existing code for me usually didn't amount to
more than adding parentheses around print statements. The proper support for
unicode alone was enough of a reason to upgrade for me.

~~~
NuSkooler
The bigger issues of upgrading I've run into: * Systems generally still ship
with 2.7x * Dependencies that also have not upgrades (e.g. 3.x doesn't exist)
or require a complete re-work now * Searching for help on X often results in
2.7x help

I've upgraded projects, but this "you refuse to upgrade" business bothers me.
There is a reason people haven't: The way Python handled all of this is
horrid.

It's often easier to just move to another language.

------
Fej
Does anyone use 2.x _by choice?_ I've only seen it required as to not break
legacy code.

~~~
chestervonwinch
Yes. My reason is that I simply don't really care that much. It's the default
on all my systems, so why bother putting in the effort to use something that
doesn't appear to offer much advantage to me personally? I use python for my
personal research, so my particularly situation affords me this laziness.

edit: I don't mean this as a knock on py3. All I'm saying is that my situation
and uses for python allow me to be apathetic towards 2 vs. 3.

~~~
iak8god
I'm in similar situation wrt what I use python for, and suffered from the same
apathy until quite recently. Man, it was _really_ easy to switch, and
completely worth it just for the little things (like UTF-8 as default encoding
for strings). It's really painless, but if you want to ease into it, I
recommend using __future__ in your py2 stuff for now just to get you into a
py3 state of mind:
[https://docs.python.org/2/library/__future__.html](https://docs.python.org/2/library/__future__.html)

~~~
Animats
UTF-8 isn't CPython's default encoding for strings. The internal encodings are
ASCII, UTF-16, or UTF-32, depending on the widest character in the string.

I would have made UTF-8 the internal representation, and generated an array of
subscript indices only when someone random-accessed a string. If the string is
being processed sequentially, as with

    
    
        for c in s :
            ...
    

you don't need an index array. You don't need them for list comprehensions or
regular expressions. One could even have opaque string indices, returned by
search methods, which don't require an index array unless forcibly converted
to an integer. Some special cases, such as "s[-1]", don't really need an index
array either.

~~~
collinmanderson
I agree. Go does something similar (using UTF-8). The Go creators _invented_
UTF-8, so I trust them. :)

~~~
Animats
Go uses UTF-8 internally, but you index a Go string by bytes, not glyphs or
graphemes. The "index" function on strings in Go returns an integer, not an
opaque index object or a slice. You can create a slice of a UTF-8 string which
is misaligned and not valid UTF-8.

Indexing a string in Python 3 returns glyphs (which are strings), not bytes.
Not graphemes; if you index through a Python 3 string with emoji that have
skin color modifications, you'll get the emoji glyph and the skin color
modifier as separate items.

Python 3 also has a type "bytes", which can't quite decide whether it's a
string type or an array of integers. Print a "bytes" type, and it's printed as
a string, with a 'b" in front of it, not as an array of integers. But an
element of a "bytes" array is an int, not a bytes type. This is for backwards
compatibility; it's roughly compatible with legacy "str" from Python 2.

Rust struggles with this. Rust tries to prevent you from getting a invalid
UTF-8 string. The solution used involves re-checking for UTF-8 validity a lot,
or bypassing it with unsafe code. This gets messy.

~~~
steveklabnik
> The solution used involves re-checking for UTF-8 validity a lot,

You only need to check once, at the boundary of when you're converting from
something that may or may not be UTF-8 to a UTF-8 string.

------
flavio81
TL;DR:

 _The important stuff that makes a good case for Python 3:_

\- Adittion of "yield from" allows easier programming with async I/O "a la "
Node.js (using 'await')

\- Standarized annotations of function arguments and return values can help in
the future for type checking, optimization, etc.

 _Even more important stuff_

\- Unicode can be used in symbols. You can now use Kanji characters in your
function names, to annoy your coworkers and win the International Obfuscated
Python Code Contest.

 _Other stuff_

\- Minor unimportant stuff that is definitely no reason alone for switching
for Python 3.

~~~
tutufan
Of those, only the async I/O stuff seems compelling. But compelling it is, at
least as used in Curio. It feels like this is still shaking out, with the
standard library and Trio (?) alternatives, but it looks really cool.

~~~
asdfgadsfgasfdg
If you work with international users full unicode support is very compelling.

~~~
loeg
Why do your users care about symbols internal to your code?

~~~
eyelidlessness
They don't, they care about `str` being unicode and developers not having to
do additional work to support unicode strings.

~~~
flavio81
Strings can be unicode in Python2, you start a unicode string with u".

Python2​ has full unicode support. While Python3 supports _only_ unicode
strings.

~~~
eyelidlessness
I was thinking through my response to this, and realized that I would just be
repeating what I already said.

Is there _any_ reason to require extra work to support unicode strings?

~~~
asdfgadsfgasfdg
I've come into large python2 projects which had been started with non-unicode
strings (because the initial developers didn't think about it). At some point
a user with non-English characters invariably signs up and then shortly
complains. It has been significant work to (1) convert everything that should
be converted to unicode (2) re-train the developers to use the unicode syntax.

------
AndyMcConachie
Read this and then realized a bug I was chasing in some Python 2.7 code was
actually because I was comparing a Long with a String :)

Thanks for helping me solve my bug dude!

------
gshulegaard
Quite a nice presentation!

But I just wanted to point out that the title is a bit presumptuous. I don't
refuse to upgrade to Python 3, it's that the default Python for most
distributions is 2 (sometimes as far back as 2.6). If you want to write a
user-space tool with Python you can either require additional dependency
setup, bundle a full interpreter with your package, or just write Python 2.7/6
code that is forward compatible with Python 3...in which case I still can't
use the new features of 3.

At the end of the day, the continued slow adoption of Python 3 today is
because ecosystems move slowly. Not to mention the original releases of Python
3 were really rough around the edges (such as being slower than Python 2.7
until ~3.4) which definitely contributed to the slow adoption in the early
years.

~~~
mixmastamyk
Python 3 has been available on most dists for 5-10 years.

~~~
gshulegaard
What I said was the _default_ version of Python is old on most distributions.

For example, CentOS 6 ships with Python 2.6 out of the box. Even faster moving
distros (like Ubuntu) are still trying to make Python 3 the default (although
at least Ubuntu ships with both 2.7 and 3.4+ out of the box).

~~~
mixmastamyk
Centos 6 is 7 years old, if you are still using that it is unfortunately your
problem. It's not hard to write "python3" on a modern dist.

Ubuntu has 3.5 and 3.6 is easily installable though not yet default 3.x.

~~~
notsrg
You think someone is going to start a new project and use a 7 year old OS? I
don't think it's "unfortunately my problem" when biz/client reqs for a 7 yo OS
are completely out of my hands, unless of course the mindset is "use Python 3
or die trying".

~~~
mixmastamyk
And the other 96% of us can move on, no need to act like you're the majority.

Py 2.6 is already EOL for almost five years.

~~~
Volt
>no need to act like you're the majority

Is he making that assumption, or are you?

~~~
mixmastamyk
Let me reiterate, a 7 year old version of EOL software. Yes.

------
maerF0x0
@OP tag this 2014 [https://github.com/asmeurer/python3-presentation/blob/gh-
pag...](https://github.com/asmeurer/python3-presentation/blob/gh-
pages/slides.html#L1021-L1023)

Feature 0: Matrix Multiplication

Feature 1: Advanced unpacking

Feature 2: Keyword only arguments

Feature 3: Chained exceptions

Feature 4: Fine grained OSError subclasses

Feature 5: Everything is an iterator

Feature 6: No more comparison of everything to everything

Feature 7: yield from

Feature 8: asyncio

Feature 9: Standard library additions

Feature 10: Fun (Unicode variable names etc...)

------
cpburns2009
This presentation could use some navigation buttons.

~~~
edoceo
The buttons are on your keyboard. Swipe on touch interface

~~~
web007
I don't expect to have to use my keyboard to navigate a webpage. It's also not
discoverable or prompted in any way.

~~~
coldtea
Using the arrows keys for the slides has been a standard since the dawn of web
presentations, a decade or so ago.

Doesn't have to be more discoverable imho. As soon one finds it out, they can
use the knowledge for any other presentation they chance upon -- and
presentations remain clutter free, without prompts and extra navigational
buttons for the rest.

~~~
jonknee
> Using the arrows keys for the slides has been a standard since the dawn of
> web presentations, a decade or so ago.

So have arrows icons you can click to switch slides... Such as on Slideshare
(coincidentally a decade old!).

~~~
jessaustin
If the icons disappear as soon as I use my keyboard or tap, that wouldn't be
too terrible.

------
iandanforth
Asyncio is the most important feature of 3.5+ imo. I'm not sure why this is
buried at #8.

~~~
jessaustin
Perhaps this comment has something to do with that burial: " _Not going to lie
to you. I still don 't get this._" Personally, the most confusing thing about
that code is that apparently _return_ will wait on a _yield from_ , which
seems odd.

~~~
AgentME
Python 3.5+ supports the async/await syntax which is much easier to follow
than _yield from_. I fully expected async/await to be item #1 of a list of
Python 3 killer features over list comprehension doodads; it's surprising that
it's entirely missing from this list!

------
ericfrederich
From:
[http://www.asmeurer.com/python3-presentation/slides.html#55](http://www.asmeurer.com/python3-presentation/slides.html#55)

... why is this good:

    
    
        def dup(n):
            for i in range(n):
                yield i
                yield i
    

... but this one better?

    
    
        def dup(n):
            for i in range(n):
                yield from [i, i]
    

... it would seem you're needlessly creating (1): another level of generators,
and (2) creating a real list

~~~
kzrdude
Compare these instead:

for i in range(n): yield i

yield from range(n)

~~~
falcolas
Both seem quite readable, really.

Seems similar to the usual "list comprehensions vs. for loop" arguments; to
which I always think "use whichever is readable for the given code".

~~~
marcosdumay
The thing about "list comprehensions vs. loop" is that you can compose
comprehensions, but you must edit loops to change them.

I fail to see how anything similar would apply here.

------
xutopia
I'm impressed how much Python seems stuck on older versions. What went wrong?

~~~
problems
It was source-level incompatible with older code so it couldn't be used as a
smooth transition like... almost any other language upgrade I've ever seen.

Breaking code like this was a big mistake in my opinion - it resulted in many
people sticking on the old version for code and library compatibility. There
are _still_ libraries which don't work on Python 3, though now fairly few of
them.

In addition to that, the unicode changes were in my opinion another mistake -
they made it far more complicated to deal with strings and byte arrays as now
even for the simplest of applications you have to put thought into character
encodings. Another annoyance for me personally is that I often use python to
do things like hex and base64 encoding, the removal of .encode("hex") really
wrecked this one for me. Now I have to remember weird import libraries like
"binascii" with weird function names like "hexlify".

Ultimately Python 2 works. And it works well, there just aren't that many
compelling reasons to move to 3 given that it often is more complicated and
breaks existing code. They have a few cool things now, so I sometimes use it
for new code but there's still nothing that's making me want to delve into a
port of my older codebases.

~~~
chc
> _It was source-level incompatible with older code so it couldn 't be used as
> a smooth transition like... almost any other language upgrade I've ever
> seen._

Ruby released the source-incompatible Ruby 1.9 just months before Python 3.
IIRC most versions of Swift have been source-incompatible with each other.
Even a language as buttoned-down as C++ has made source-incompatible
changes[1]. I have no idea where people got the notion that Python invented
the idea of breaking changes, but it just isn't so.

[1]: [https://stackoverflow.com/questions/6399615/what-breaking-
ch...](https://stackoverflow.com/questions/6399615/what-breaking-changes-are-
introduced-in-c11)

~~~
problems
Go ahead and look at those breaking changes, then compare with Python 2 to 3's
breaking changes.

It's a difference of a few minor things versus a whole swath of changes to the
handling of strings in the language, heck, a python 2 print statement isn't
compatible with python 3.

These are much more significant breaking changes which make porting code much
harder than any of the other examples you've given. For the most part,
developers don't have to touch or only have to make minor changes for specific
cases to port to Ruby 1.9 or C++11 - look at those C++11 changes for example,
so few people were doing those things and they're such bad practices that it
simply didn't matter. They successfully preserved compatibility in the nominal
case. But even following all the best practices in your Python 2 code will not
make it run under Python 3.

~~~
chc
I don't use Swift or C++ much, but I have several years of experience in both
Ruby and Python. The changes in Python might be a bit bigger, but the changes
in Python 3 and Ruby 1.9 seem of roughly the same magnitude to me. Text
encoding is now a problem you need to think about, some methods were removed,
other methods were added, the output of some methods changed (e.g. the output
of Array.to_s, the result of indexing a string), a few syntactic constructs
changed (e.g. character literals used to return numbers, now return strings),
and all C-based libraries broke in Ruby 1.9. In both cases, more than 99% of
your code will probably be the same (unless your program is mostly print
statements, I guess). What's more, Python took more pains than Ruby to ease
the upgrade process, with stuff like __future__ imports, 2to3, and the six
library. IIRC the Ruby team just changed stuff and said, "OK, update your code
accordingly and we promise not to do this to you again for a long time."

It seems to me like the primary difference that made the Python upgrade worse
is that the authors of the big libraries in Ruby were enthusiastic about
moving to Ruby 1.9, so that it was possible to start porting most Ruby apps
very soon after 1.9 released, while a few big Python library authors dragged
their feet on even getting started. This was a very real problem, but it was
essentially a cultural problem of the library landscape being very different,
not a matter of the language itself being drastically different.

------
jxramos
Glad to see the Enum class made the list. We've put them to good use in our
codebase, especially the Flags enum variant which gives as a powerful summary
feature to annotated data samples with all the sorts of flagging information
we want to tack around it.

------
ptx
The slides on chained exceptions (feature 3) are missing one thing, I think.
The "raise from" example is not really a way to "do this manually", but rather
a way make explicit the relation between the two chained exceptions (as can be
seen in the traceback messages), which is quite helpful.

The first example says that one error occurred, we tried to handle it, but
then another error occurred in the handling. E.g. "Failed to find eggs in
refrigerator. Tried to buy eggs, but tripped and broke leg."

The syntax in second example should be used when the exception in turn causes
a larger process to fail, e.g. "Failed to make pancakes due to a failure to
find eggs in refrigerator."

------
alanfranzoni
I still don't think that any of those new functions justifies the need of a
total compatibility breakdown, like the one that was artificially induced from
python2.7 to python3.

Python3 is good, but should have happened as a smooth transition from
python2.7. The way it was handled was just a mess, and still keeps polluting
the Python world.

Next time somebody asks what Java has over Python... here it is: nothing like
the python 2 vs 3 mess.

~~~
phire
Honestly, if they had just keep the print statement, the push back would have
been almost non-existent.

It was that one change that pushed python 3 from "some programs and libraries
will need to be written" to "almost every single program and intro to python
tutorial needs to change".

~~~
seanwilson
How hard would it have been to allow Python 2 and 3 code files to be mixed?

~~~
minitech
That’s a giant can of worms. One example problem: Python 2 has a type of class
(old-style) that doesn’t exist in Python 3. What happens when you try to pass
this type of class or one of its instances between the languages? There’s a
bunch of stuff like that. You’d end up with a very weighed-down interpreter
with a bunch of caveats if you ended up with one at all.

~~~
seanwilson
Would doing that then deprecating those features after 5 years or so not be
better than what's happened with the Python 3 transition? I'm curious what
options there are for how to make such a transition smoother.

~~~
minitech
The important part of Python 3 is the bytes/str/unicode rework, and there’s no
way to make that not a breaking change. Everything else is minor stuff that’s
allowed to be breaking because the str change already broke backwards
compatibility.

(And yes, making strings text rather than bytes was really that important.
Python 3 would be a huge improvement even if it were only that and some other
safety things like removing the default ordering of incompatible types.)

------
iainmerrick
The new keyword-only arguments look great, but it looks like it relies on
adding a " * " parameter that allows any number of arguments. What if I want
the safety of keyword-only arguments, but I _don 't_ want varargs? Is there a
way to do that?

~~~
arximboldi
This is covered in the link. Just put a * without a name, as in

    
    
      def foo(*, x=None, y="")
    

(Edit) The specific slide:
[http://www.asmeurer.com/python3-presentation/slides.html#16](http://www.asmeurer.com/python3-presentation/slides.html#16)

~~~
dozzie
Oh my, it looks atrocious.

Almost every time I see something introduced in Python 3 I have an impression
that current Python envies Perl its baroque semantics, except that Perl
usually tries to guess what the programmer meant, while with Python the
relationship is reversed: the programmer needs to guess what the language
wants.

Python's main selling point was simplicity of syntax and semantics that
preserved its high-level language status. This simplicity is no longer present
in 3.x line.

~~~
dom0
Python 2 is a vastly more complex language compared to Python 3. Just try to
name the basic classes of types that exist in Python 2.

Hint: Cannot be counted on two hands.

~~~
dozzie
Well, try this for me, especially that you didn't use searchable terminology,
so it's hard to confirm what you're saying. And then tell how much of that is
important for typical code.

~~~
dom0
Python 2 has old-style classes, new-style classes, functions, bound methods,
unbound methods, slot wrappers, descriptors, method wrappers, built-ins, ...
and I'm rather certain I forgot some. All kinda callable types I mentioned
behave differently. This makes the language complicated; and due to the
dynamic nature leads to subtle bugs that are only detectable at runtime.
Python 2 is a lot like C there. This isn't limited to callables but is spread
around the language in a lot of places. Python (both 2 and 3) is not a simple
language. It has a supremely complicated data model whose documentation is
insufficient and scattered.

------
matthewmacleod
Ruby's 1.8 to 1.9 transition seemed to go much smoother - I'm curious what the
difference is. Just down to what is essentially better source comparability I
guess.

~~~
dragonwriter
Ruby 1.8 to 1.9 was a similar mess for a shorter period of time, and not
because it was handled better, but because there was less diverse entrenched
code and subcommunities to deal with: when Rails and popular Rails libraries
worked, most of the community could move; Python had a whole lot more that had
to be addressed, the curse of it's broader success.

(Also, being already expression-oriented, Ruby didn't have to deal with
running into problems where a core feature was a statement that couldn't be
used in contexts limited to expressions; fixing that is inherently painful.)

~~~
TylerE
Didn't Ruby 1.9 also offer a meaningful performance boost as well? Whereas
early Py3 was actually about 5-10% slower than Py2.

------
jtchang
Just wondering but what should you do if you decide to go with Python 3 and
find a library you want to use that isn't compatible and you are short on
time?

~~~
dr_zoidberg
That fear held me back 7 years ago when I started learning Python. In 2017,
having worked in many projects, what I have to tell you is this: I never found
such case where Python 3 wasn't supported, and I should've learned Py3 to
begin with. YMMV, but the fear was unfounded back in 2010, and even more so
today.

There are very few projects without Py3 support, and most you'll find without
Py3 support is because the project has been dead for quite some time.

~~~
xrange
>There are very few projects without Py3 support, and most you'll find without
Py3 support is because the project has been dead for quite some time.

One notable exception is FreeCAD for anyone who is looking to jump into a
project to help with the transition from python 2 to 3.

------
mahyarm
It's funny how the differences between python 2.7 & 3.x is less than swift 2
to 3, yet python stays in 2.7 land forever.

~~~
saghm
Probably because there was a lot less Swift code than Python in the wild at
the respective times each came out with the new version, so having everyone
upgrade all the old, incompatible code was less daunting.

------
flavio81
It seems i also can't scroll to the next page on this slide "because i refuse
to upgrade to Python 3"...

------
KaiserPro
thus, python did jump the shark.

The biggest thing that python _needs_ is proper multithreading.

The rest is nice noise.

------
JupiterMoon
Open page. Nothing works. Enable their scripts. First slide shows but nothing
works - except the link to the pdf version.

Why not give a link to the pdf version in a <noscript> element?

~~~
giardini
Works for me! when I hit <enter> or right-arrow it goes to the next slide,
<left-arrow> for previous slide.

~~~
JupiterMoon
Tried all of these - as well as space :(

------
assafmo
I'm not touching python like it was fire since it threw
YouHaveAMissingTabSomewhereException at me 6 years ago.

And it always pisses me off to see a python source code all lower case.
Someone would think upper case letters cost money and underscores are a must
like a lemon in a corona.

Am I the only one?

~~~
tripzilch
Who can't _touch_ fire? No ... ?

But yeah syntactic whitespace was a thing to get used to for myself over 10
years ago as well. It's no big deal and it works great (imho).

------
SeanDav
Alternative view titles:

 _Zero - The Number of Applications that Can only be Developed in Python 3_

or

 _7456324 - The number of companies that only use Python 2.x_

Although these made up titles are slightly tongue-in-cheek, they do server to
illustrate that for me at least, I do not have a compelling reason to switch
to Python 3.

~~~
teilo
That's also a meaningless argument. It's true of any turing-complete language.

~~~
SeanDav
> _" That's also a meaningless argument. It's true of any turing-complete
> language."_

Title 1 of course. Title 2 is a far more compelling reason to stay with Python
2.x. If I program for fun, then Python 3 is definitely worth playing around
in, but for professional development, everything I do in Python is done in
Python 2.x. That is not a theoretical argument, that is fact.

~~~
minitech
> for professional development, everything I do in Python is done in Python
> 2.x. That is not a theoretical argument, that is fact.

And everything I do professionally in Python is done in 3.x as of this
January. Also fact! Industry standards sometimes move slowly, but they are
moving.

