On Thu, May 19, 2016 at 11:15 AM, Jacob Scott <jacob.sc...@gmail.com> wrote: > I think I would be (perhaps pleasantly) surprised if there was a wide gulf > between Python 2.7 and Python 3 *in terms of advice/resources applicable to > my original question*. Based on my (admittedly shallow) understanding of > overall Python 2.7/3 differences, the biggest changes (from e.g. > http://sebastianraschka.com/Articles/2014_python_2_3_key_diff.html) tend to > be a bit lower level (utf-8 str) than what I'm focused on (maintainable and > testable classes, functions, modules, etc).
It's not really about UTF-8 (and the article you link to is flat wrong in describing Py3's str type as UTF-8); it's about the recognition of a fundamental difference between text and bytes. Looking at it another way: Python 2 lets you pretend it's all easy, so long as you're working with the simple Latin letters A-Z and a-z, but when you need anything else (other alphabets, non-ASCII symbols like dashes and quotes and emoji, diacritical marks, etc, etc), Python 2 doesn't help you at all, and suddenly you're on your own. Python 3 forces you to think up-front about things (a little bit of extra work/hassle), but then gives you all the world's languages for free. That's a very high level feature: you ask a user to enter his/her name, and instead of requiring that it be English without diacritical marks, you can accept (almost[1]) anything. Sometimes, UTF-8 lets you *pretend* that Python 2 (or C or PHP or whatever other language you pick) can handle all those other characters too, but it's a massively leaky abstraction. The other broad change in Python 3 is a shift in focus from concrete lists to lazy objects. In Py2, range() returns a list of numbers; in Py3, it returns a "range object", which functions just like that list in many ways (subscripting, iterating, etc work the same way), but is far more memory-efficient on huge ranges. In Py2, a dictionary's keys() method returns a list; in Py3, it returns a special view object. That kind of thing. Quite a few of the other differences mentioned in that article are actually the removal of already-deprecated syntax. For instance, the 'except NameError as err:' syntax works in 2.6 and 2.7 as well as 3.x, and is the recommended way to spell it (unless you need to support ancient Pythons - 2.5 is pretty old now, but some people do support it). For backward compatibility, all of the 2.x line still supports the old syntax, but new code should be using the reliable syntax - the comma is ambiguous (what if you wanted to accept more than one exception type?). Similarly, you shouldn't be calling an iterator's .next() method directly; always call the built-in next() function. Python 3 made this a lot clearer by renaming the method to __next__(), which clarifies that this is a "magic method" or "special method. Dunder methods are for defining, not calling. (Rule of thumb, not entirely true, but close on.) For the rest, Python 3 basically has the advantage of six additional years of development time. That's given us features like exception chaining, core support for virtual environments, a variety of new stdlib modules, support for asynchronous I/O, a new multiplication operator, and soon (3.6), interpolated string 'literals' (more like a list comprehension than a string literal). And that gap is ever widening. Using 2.7 means abandoning all those features. It's still in support, but it's bug fixes and security patches only - which, as the Red Queen explained to Alice, is where you have to run as fast as you can just to stay in one place. ChrisA [1] Some people's names can't be represented in Unicode. But excluding those names is a lot less significant than excluding the huge proportion of people whose names aren't representable in ASCII. -- https://mail.python.org/mailman/listinfo/python-list