New features you can't use unless you are in Python 3
asmeurer.com
asmeurer.com
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.
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.Also in 2.4 if you assign a variable to a local inside a traceback it might leak memory.
I didn't know that too. It's pretty cool. Seems like they overload __truediv__ operator: https://github.com/python/cpython/blob/master/Lib/pathlib.py...
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.
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.
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.
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.
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."
I've worked for a while on a C++ vector/matrix library which made good use of C++'s capabilities to overload operators. It all made sense, in the beginning. But as time wore on and more and more exceptions crept in you'd get very confusing bits of code where in the same fragment '+' would mean one thing, then another, ditto for '*' and endless frustration when no free operator could be overloaded and in the end you'd end up having to call a function anyway.
Maintaining that over the years got less and less pleasant, even if at the start it was probably some of the cleanest code for the limited purpose that it had.
Personally, I avoid operator overloading, just as I try to avoid reader macros and other clever bits. It's not that I don't know how to use them or how they work, it's that I love being able to look at a piece of code without also having to study the environment it operates in in order to know what it does.
KISS. Though, adding two vectors or multiplying a vector and a matrix with just an operator looks very good. Better than:
result_matrix = vec_mat_mul(some_vec, some_matrix);The problem here seems to me to be “having too small a space of valid operators in the host language for the problem domain” more than “operator overloading”, as such. But it's true that the space of available operators is a factor in whether you should use operators over functions for a particular use, because it definitely impacts clarity.
IMO, ideally a language should support a wide range of operators, a d programmers should be very selective in how they use them; additionally, overloaded operators in libraries intended for reuse should usually have equivalent text-named functions/methods, for when the library is used in contexts where using the overloaded operators would be confusing. (Ideally, you'd be able to import selectively so that you don't even bring the operators in scope where you don't want to use them.)
Ok, but in that case you need two systems to access the same code, that only adds to the confusion and really negates all upside from having the overloaded operator in the first place.
That violates DRY in a very ugly way.
Anyway, I think we can agree on one thing: operator overloading is something that one should not do just because it is possible, but only for very good reasons.
Does that work?
I don't think aliasing (or the moral equivalent, where operator vs. method/function can't be an alias from an implementation point of view) violates DRY. Presenting an alternative API for different use cases isn't repetition.
> Anyway, I think we can agree on one thing: operator overloading is something that one should not do just because it is possible, but only for very good reasons.
We agree on that.
Ken Iverson would probably disagree.
Judging from its surviving successors (J particularly), the reason is “keyboards” not “operator overloading”.
Every single time I see printing to an IO stream in C++ I think 'why are they bit-shifting that... oh right'.
Here's C's operator precedence.[1] All 15 levels.
Think of the maintenance programmer who will have to fix this.
[1] http://en.cppreference.com/w/c/language/operator_precedence
People have experimented with relative precedence levels (and I believe Perl6 does this?) where you can say “this is lower-precedence than that” and you have to use parentheses to disambiguate expressions that mix operators unrelated by that partial order.
Seems that this set of slides (which were very informative!) is for up to 3.5
The answer is there are 3 ways to format a string: %, .format, and f-strings.
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.https://pypi.python.org/pypi/pysubnettree
Last time I played with it, it didn't like Python 3 or ipaddress, though. I see a recent upload, so maybe they addressed that.
just try: socket.inet_aton
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.
It actually become usable somewhere around 3.2/3.3, released in 2011/2012.
- 2008-2012: Becoming actually usable.
- 2012-2016: Libraries porting over
- 2016-2020: Applications porting over (more work needs to be done here. See http://portingdb.xyz )
By count of lines, 0.04% of Python code I've published exists only to deal with 2 vs. 3 issues. Of that code, 34% consists of importing and applying a decorator from Django that handles setting up either __str__() or __unicode__() on a Django model as appropriate. Tellingly, there are exactly two lines I could find that aren't that decorator and which deal with a str/unicode issue.
And that's in code which doesn't just run on Python 3, it supports 2 and 3 in the same codebase.
Things I still have in Python 2.7:
- Code that runs on low-end shared hosting. There's a Python 3, but it's 3.2, the least-compatible version. No "six", and "u'xyz' isn't allowed.
- ROS, the Robot Operating System. Python 3 support is coming, but it's not really here yet.
I converted over the dedicated servers and some IoT stuff a year ago.
The types stuff probably should have been called Python 4, not Python 3.6. Those are major language changes. The optional-types-that-are-not-checked thing seems a bad idea. I can see having checked types; that allows some important optimizations. When you know something is a machine type, such as an int or float, you don't have to box it. But the feature of type declarations without checking is a foot gun.
*van Rossum
I wouldn't say that's an accurate statement of what Guido does every day :)
(nb: I work at Dropbox, and have worked with Guido at Dropbox.)
[1] https://www.quora.com/What-version-of-Python-does-Dropbox-us...
From https://gvanrossum.github.io/ :
But when my last name is used alone to refer to me, it is capitalized, for example: "As usual, Van Rossum was right."
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.
I hear some people really really prefer `print as statement`, but I've never seem them in real life.
I really hope someone makes this work. I literally laughed and thought that it was a troll the first time I saw the future print import and that being used as a compelling reason that I should switch to Py3.
print "Text",
For those not familiar with Python 2's syntax: that trailing comma is significant. And it's pure syntax; it's not the creation of a tuple either… print >>sys.stderr, "Spam"
Whereas in the new print function it's a keyword argument: print("Spam", file=sys.stderr) print(“Text”, end=“”)
is verbose. Not too verbose, but considering how often I write prints as temporary throwaway code, every little bit hurts…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.
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.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.
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.
I am pretty much in the same situation and in hindsight I kinda wish I upgraded a little sooner. Fixing print brackets was the biggest (not that big) task, and from there on it was all python3 sugar for me :)
In my experience, the most you are doing is shifting around imports (urllib, for instance), declaring classes slightly differently, handling string encoding differently, or printing, format-ing, and raising exceptions slightly differently (and in a more sensible syntax for all, imo).
On the contrary, there are new modules that you are missing out on and you will regularly run into "it's in the stdlib" answers that are not applicable to you.
If you are maintaining a large or important codebase rather than working as a hobbyist or independent contractor, then there is nothing wrong with using older languages/platforms, especially if they are stable and well tested. Avoiding surprises or breakage is generally a lot more important to you than getting a cool new list comprehension facility. Actually, stability of the language is something to be desired, as there is a cognitive cost to having different portions of the project use different language constructs.
In terms of python 2 not being supported in the future, if we are forced to stop using python 2, we'll probably need to switch the project over to Java. Not something I'm looking forward to, but at least the java community doesn't force developers to rewrite their source code when a new JVM comes out. There were some examples of older bytecode not working in newer JVMs, but as long as you had the original sources you could always compile to the newer bytecode. Personally, I've grabbed jars from 2005 and used them without any issue. My employer is mostly a java shop, and I already have to occasionally answer questions from other devs about why this project is in python. My answer has always been that python is a more productive language for this use case, and their retort is that it's not really enterprise ready -- meaning things like stability and support, so that while the language may be faster to initially develop in, the long term maintenance cost will be higher. The lack of respect for backwards compatibility as well as the hostility of the community to basic things like don't break working code is causing me to lose some conviction in my side of this argument. I imagine the same discussion is happening in businesses all over the country.
The question is not python 2 or python 3, but python 2 or move away from the language to one that understands my needs. This transition has created a real black eye for python and its role in the commercial space -- at least that's my impression.
This is just silly. It will take at least 100x more effort to rewrite the project in Java than it would to upgrade to Python 3.
> at least the java community doesn't force developers to rewrite their source code when a new JVM comes out
Yes, that was an unfortunate, one-time thing for Python that happened almost a decade ago.
> My employer is mostly a java shop ... and their retort is that [python is] not really enterprise ready
Yep. That sounds like the kind of nonsense people say in a Java shop.
Yes, but in return it will bring a 10x performance improvement in lots of areas, and the option of a whole lot more sturdy statically checked code.
mypy is a much better type system than Java, btw, if that's what you're after.
There are downsides though: type stubs are of... varying... quality, there are ugly hacks needed to resolve cyclic imports and the type annotation syntax gets yucky in places, even in 3.6.
I'm using mypy seriously for about a year and it's progressing very well. I see very good ROI even with the uglification of the code.
Haven't checked, but I find it absolutely possible that there's one (or more).
You say it as if that would be a strange position to be it, but it's a common situation. A lot of time you start with the faster to prototype / more familiar language, and outgrow it.
That's what companies do after they grow so much that a language such as Python/Ruby/PHP is not doing it for them anymore or wont be doing it soon with their growth trajectory.
And you don't have to be Twitter scale either.
Even if you have moderate growth, you might find that with a different language, you can use 1/10 the servers, and thus drastically lower your operating expenses.
So, when some of those companies face the jump to Python 3, and the required rewriting, they often decide to bite the bullet, and do a fuller rewriting in another language (like Java, but Golang is also getting many Python converts, including e.g. Dropbox IIRC), that will give them much more bang for their buck.
I know that a sibling mentions the ridiculousness of the situation, but a forced depreciation of the Python 2 runtime (see also, Windows) is a billable, justifiable, reason to do the work of refactoring parts of the system. I do not expect those billable hours to happen in the next decade, however.
Maybe one way of thinking about it is to take a hard drive full of data and randomly flip a few bits. Then ask what the effort is to find and fix all the errors, and whether this effort is a function of the number of bits flipped or the size of the drive. The people who don't understand/have sympathy with my concerns are saying -- it will only introduce a few breaking changes -- but I'm looking at the size of the project.
But this condescending attitude coming from some in the python community really isn't helping the language any. I am not saying that everyone has to share my concerns, but they certainly aren't "nonsense" or "ridiculous".
If your code base is a big pile with no tests.. well you dug that grave.
I'm sorry to be the one to break this to you friend, but you must be suffering from the Java shop version of Stockholm Syndrome.
Java contains a lot of ugly legacy bullshit because of that.
Joel Spolsky talks about this desire for artistic purity over useful backwards compatible cruft in a couple of nice essays:
https://www.joelonsoftware.com/2000/04/06/things-you-should-...
https://www.joelonsoftware.com/2004/06/13/how-microsoft-lost...
Anaconda Python really should be more popular on OS X and Linux than it is. Homebrew is okay, but a little bit wonky for Python packages.
I just tried again and saw an error similar to what I get when I try with pip+brew - ModuleNotFoundError: No module named 'PyQt4'.
Note, this is after spending quite a while installing/removing/upgrading various qt packages and dependencies to try to resolve this. The system might be in a weird state because of that - but I originally started from scratch and only followed the instructions I found on the matplotlib site...
* I work a lot with low level data and I prefer strings to be an array of bytes. The forced unicode support is stupid for all my use cases. Also Unicode in 3.x support is rather flawed: http://www.cmlenz.net/archives/2008/07/the-truth-about-unico...
* Major APIs now return iterators or views instead of simple lists. This is rarely justified introduces unnecessary complication in many cases. Everybody knows list, why not keep it simple. I can't count how often I list() all the things just to get things going and because I didn't bother to look up the API to check what types are returned.
* I have to convert a lot of clear text data formats and needing to use 'print(x, end=" ")' instead of a simple 'print x,' is really cumbersome. I think printing something is absolutely substantial and it is justified for "print" be a statement.
* There is a distinct performance loss if you directly compare 3.x to 2.x at least for all my use cases.
* The sudden harsh break of backwards compatibility was completely unnecessary and stupid. Why not introduce new features slow and mark old features as deprecated or allow to specify the version in the header. There are a lot of ways one could handle this better.
* Python 3.x may be a marginally better (e.g more consitent) language than 2.x. For me it only introduces inconveniences. It takes a huge amount of effort to port code from 2.x to 3.x (if you want to keep it clean and readable). The practical benefits are close to zero (and you even loose performance). This is why the community seems to agree to stay with 2.x for a very long time.
bytes and bytearray are still there … if you don't want to work with unicode data in a proper Unicode type, you don't have to. But it doesn't follow that the rest of us that do want a good type for text shouldn't be able to have a good type / tooling for that.
(If you mean that functions that take text require text as input now, well, yeah.)
> Also Unicode in 3.x support is rather flawed
The entirety of "Internal Representation" is out of date, and no longer correct. For just about every other section, I believe libraries readily exist in PyPI to solve those problems. I do agree that it would be nice to have some of that closer to the standard library.
> I have to convert a lot of clear text data formats
I find it strange that you work with text formats, but you dislike having a proper text type? Even if you data were mostly or all ASCII, Python's text handling would still be mostly transparent, just silently doing the right thing if non-ASCII ever were encountered.
> I think printing something is absolutely substantial and it is justified for "print" be a statement.
I'm going to disagree. Python 2's print statements special syntax just adds cognitive load to reading, and to newcomers encountering such syntax, that just doesn't need to be there. Further, the trailing comma for "no EOL" is too subtle from a readability perspective.
> Major APIs now return iterators or views instead of simple lists. This is rarely justified introduces unnecessary complication in many cases.
The old APIs forced materialization of an iterable to a list, and there are plenty of circumstances where this just isn't required. This results in higher memory usage, for that list. The list() also makes it explicit where such materialization happen.
You can always get a list from an API/function that uses generators. You can't go the other way.
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.
Python2 has full unicode support. While Python3 supports only unicode strings.
Is there any reason to require extra work to support unicode strings?
Thanks for helping me solve my bug dude!
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.
Ubuntu 18.04 LTS plans on Python 3-only, but Ubuntu has been shipping Python 3.x since 13.04 and 3.x is the default with 2.x available since 16.04 , so in terms of shipping Python 3 code, Ubuntu 12.04 LTS (the last LTS where you can't assume it has a python 3) EOL'd on April 28 2017. Assuming $WORK follows EOL depredations, you should be fine for Ubuntu.
But I agree with you:
> 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.
Although, personally, I think the best thing to do is write forward compatible Python 2 code (or at least as much as you can). At the very least write Python 2 code that lends itself well to using a migration tool like 2-to-3.
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).
Ubuntu has 3.5 and 3.6 is easily installable though not yet default 3.x.
Py 2.6 is already EOL for almost five years.
Is he making that assumption, or are you?
It's not the default because /bin/python is synlinked to python2. You have to explicitly run it.
That's not very true.
- Most BSDs and MacOS still don't have it installed by default.
- RHEL/CentOS still don't have it installed by default.
- Ubuntu LTS didn't get it by default until 14.04. (3 years ago) (mainline ubuntu got it in 13.04, 4 years ago)
Not that the default install drives the whole ecosystem, but there are cases where targeting an interpreter you know will be there is helpful.
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...)
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.
So have arrows icons you can click to switch slides... Such as on Slideshare (coincidentally a decade old!).
edit 4 grammar
... 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 yield from (i, i)
It does use fewer lines, but if that's the point then this would work: yield i; yield iIn general `yield from` makes delegation inside a generator cleaner.
for i in range(n): yield i
yield from range(n)
Seems similar to the usual "list comprehensions vs. for loop" arguments; to which I always think "use whichever is readable for the given code".
I fail to see how anything similar would apply here.
<rant> i think the real split is between CPython + C-Extensions and the JIT (PyPy,Numba) gang for heavy lifting in python. I for one wish Guido would embrace the effort of integrating the GILectomy into CPython and make python thread parrallism real for CPU bound work as opposed to the high overhead multiprocessing approach.
Also, including mypy in the stdlib to make genuine optional static typing would make python a defacto standard for much of what it does now without the "we love python but...." production code pain points. </rant>
The split you mention is real, but it's existed even longer than the 2vs3 split. All the various alternate Python implementations that have come and gone or are still around with the exception of Numba were started pre-3k. I wouldn't even argue that upstream was necessarily wrong not to prioritize performance and more specific use cases (like certain production uses, or scientific uses (a lot of begging to finally get the @ operator)), it just didn't matter as much for a long time. But things are different now. There are many other very expressive and much faster (either dynamically typed or static) languages in competition that lessen Python's effectiveness at reducing dev time in exchange for more hardware. Without a more serious focus on performance, Python will be driven only by momentum. That can last a long time, and is essentially the end point anyway when performance is "good enough" compared to the close alternatives, but it's not a great look when there's still much that could be done.
Change has to be compelling. Python 3 wasn't until at least recently (3.5 and on).
Change has to be backwards compatible as possible. Python 3 wasn't, often for BS reasons.
Change better has some major selling feature. Python 3 has nothing that special over 2.
Change must come with nice conversion tools. 2to3 wasn't that.
etc...
I'm glad they did the "mediocre" fixes as well, they lead to a lot fewer encoding (and other) bugs, which were a real problem on nontrivial programs.
I didn't like how the changes to strings and bytes were made, but that's probably a larger discussion, and fits within how Py3 has evolved. If anyone is really confused by the struggle with adoption, just look through the release notes of version by version, and ask at what point there's a compelling reason to upgrade. I still don't see one, but at this point, nearly 10 years after Py3k, Py3.6 is finally usable enough that I wouldn't mind as much if I had to work on a Py3.6 codebase instead of a Py2.7 one.
I've found ordered dicts useful on a lot of projects, more than I'd have predicted in advance however.
nonlocal is another overdue fix.
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.
And while it isn't trivial, it is easy enough to just deal with bytes in 3.x.
import base64In term's of code reliability, Python 3's approach is much more sane.
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...
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.
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.
>>> import codecs
>>> codecs.encode(b'eggs', 'hex')
b'65676773'
>>> codecs.encode(b'eggs', 'base64')
b'ZWdncw==\n'And so we are stuck, especially in enterprise where it could cost a lot of time and money to port because the transition wasn't managed well, both by users and the Python team.
People just can't be bothered to upgrade when it works well enough for them.
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."
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.
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".
(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.)
def foo(*, x=None, y="")
(Edit) The specific slide: http://www.asmeurer.com/python3-presentation/slides.html#16This is a very good feature, but a weird syntax!
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.
Hint: Cannot be counted on two hands.
(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.)
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.
The biggest thing that python _needs_ is proper multithreading.
The rest is nice noise.
Why not give a link to the pdf version in a <noscript> element?
Please stop. Thanks.
Maybe if more people resisted the temptation to use the latest and shiniest frameworks where it isn't warranted, I wouldn't have to upgrade my otherwise perfectly functional hardware every five years because it just can't handle all of today's most fashionable abstraction layers over plain HTML.
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?
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).
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.
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.
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.
And by significant, I mean upwards of 40%. So, except for corporate inertia, or the rare can't-live-without libraries that have yet to be ported to 3.x (see: http://py3readiness.org), there are no compelling reasons to stick with Python 2.x for new projects.