Though Python 3 was released in 2008, many projects are still stuck on Python 2.
It’s understandable that porting large existing codebases to a new version is a prospect which sends a shiver down many a developer’s spine. But code inevitably needs to be maintained, and so when all the shiny new features that would fix everything are in a new version, is it really worth staying rooted in the past?
We’ll take you through some of the features that Python 2 programs are missing out on, not only from 3.0 but up to the current release (3.7).
Why Python 3 Happened
Before 2008, Python developers had a bit of a headache. The language that started in the 1989 Christmas holidays as the pet project of Guido van Rossum was now growing at a fast pace. Features had been piled on, and the project was now large enough that earlier design decisions were hindering implementation. Because of this, the process of adding new features was becoming an exercise in hacking around the existing code.
The solution was Python 3: the only release that deliberately broke backwards compatibility. At the time, the decision was controversial. Was it acceptable for a publicly used open source project to purposefully break on older code? Despite the backlash, the decision was taken, giving Guido and the developers a one off chance to clean out redundant code, fix common pitfalls and re-architect the language. The aim was that within Python 3 there would be only one obvious way of doing things. It’s testament to the design choices made back then that we’re still on 3.x releases a decade later.
The __future__ is Now
The __future__
import is a slice of time-travelling wizardry which allows you to summon select features from future releases of Python. In fact, the current Python release, 3.7, contains __future__
imports from releases which haven’t yet been written!
Ok fine, so it’s not quite as grandiose as that, a __future__
import is just an explicit indicator of switching on new syntax which is packaged with the current release. We thought we’d mention it because a few of the Python 3 features listed below can be __future__
imported and used in 2.6 and 2.7, which were released to coincide with 3.0 and 3.1 respectively. Having said this, upgrading is, of course, still advised as new features are ‘frozen’ in past releases and will not benefit from the evolution and maintenance of current versions.
Onto what you’re missing out on in Python 3…
Print is a Function
Yes, we know that most people are aware of this, but it’s one of the most used statements by Pythonistas who are starting out. print
moved from a keyword to a function, which just makes sense.
This Python 2 code
print "Fresh Hacks Every Day" print "Foo", "some more text on the same line as foo"
will become the following in Python 3.
print("Fresh Hacks Every Day") print("Foo", end='') print("some more text on the same line as foo")
Souped up Unpacking
Here we have a tuple containing some data. In Python 2, we can already unpack into different variables like so:
person = ("Steve", "Hammond", 34, "England", "spaces") name, surname, age, country, indent_pref = person
But let’s say we only care about the first name and indentation preference. In Python 3, we can now unpack like this:
person = ("Steve", "Hammond", 34, "England", "spaces") name, *misc, indent_pref = person # These would also work name, surname, age, *misc = person *misc, indent_pref = person
This provides much more flexibility when unpacking — especially handy if dealing with tuples longer than the one in this example.
Unpacking is commonly used in for-loops, especially when using things like zip()
or enumerate()
. As an example of applying the new syntax, we now have a function, get_people_data()
, that returns a list of tuples like the person
example above.
for name, *misc, indent_pref in get_people_data(): if indent_pref is not "spaces": print(f"You will feel the full wrath of PEP 8, {name}.")
This works great. But wouldn’t it be nice if we could store the indentation preference in a better way than just a string? In a way similar to an enum
in C?
Enums
Enums in Python. What a treat. Due to popular demand, they’ve been in the standard library since 3.4.
Now we can define indentation preference like this:
from enum import Enum class Indent(Enum): SPACES = 'spaces' TABS = 'tabs' EITHER = 'either' person = ("Steve", "Hammond", 34, "England", Indent.SPACES) # or person = ("Steve", "Hammond", 34, "England", Indent("spaces")) # Let's try and initialise with an invalid value person = ("Steve", "Hammond", 34, "England", Indent("invalid value")) # 'ValueError: 'invalid value' is not a valid Indent
The syntax seems a bit strange, but it can be useful when dealing with numeric constants or initialisation from strings.
Division
A simple but major change: when dividing integers in Python 3 we get true float division by default (dividing two integers in Python 2 always resulted in an integer result).
This is the Python 2 behaviour:
>>> 1 / 3 0 >>> 5 / 2 2
Whereas in Python 3 we get more accuracy:
>>> 1 / 3 0.3333333333333333 >>> 5 / 2 2.5
//
can of course be used for floor integer division if this is required.
This change is one that should definitely be noted if you’re porting code from 2 to 3; it’s an easy one to slip under the radar that could cause major issues in program logic.
Chaining Exceptions
It’s very common to catch one exception, then raise another. This could be because your application has a defined set of custom exceptions, or simply because you want to provide more information about what went wrong.
Here we have a program which crudely calculates the number of days needed to be worked to earn a certain proportion of yearly pay.
class InvalidSalaryError(Exception): pass def days_to_earn(annual_pay, amount): """Return number of days worked to earn `amount`.""" try: annual_frac = amount / annual_pay except ZeroDivisionError: raise InvalidSalaryError("Could not calculate number of days") return 365 * annual_frac if __name__ == '__main__': print(days_to_earn(0, 4500)) print(days_to_earn(20000, 4500))
We can see that if an annual pay of zero is specified and a ZeroDivisionError
occurs, this is caught, and an InvalidSalaryError
is raised.
Let’s try running this with Python 2.
$ python days_calc.py Traceback (most recent call last): File "exception_chaining.py", line 13, in <module> print(days_to_earn(0, 4500)) File "exception_chaining.py", line 9, in days_to_earn raise InvalidSalaryError("Could not calculate number of days") __main__.InvalidSalaryError: Could not calculate number of days
Because we caught the ZeroDivisionError
, it got swallowed, so only the InvalidSalaryError
traceback is shown.
Now let’s run this with Python 3.
$ python3 days_calc.py Traceback (most recent call last): File "exceptions_chaining.py", line 7, in days_to_earn annual_frac = amount / annual_pay ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "exceptions_chaining.py", line 13, in <module> print(days_to_earn(0, 4_500)) File "exceptions_chaining.py", line 9, in days_to_earn raise InvalidSalaryError("Could not calculate number of days") __main__.InvalidSalaryError: Could not calculate number of days
We got a far more detailed error report, explaining what caused the InvalidSalaryError
, complete with a traceback for the ZeroDivisionError
. This is particularly useful when you’re using code written by someone else, which might not have the most verbose error messages.
We won’t go into it here, but there’s also new raise ... from
syntax which allows for explicit exception chaining.
Side note: dealing with large numbers in Python
In the above program we had to deal with int
s in the tens of thousands. Writing long numbers like 20000
or 0b001110100010
is a recipe for screen squinting. How about separating them like this: 20_000
, 0b_0011_1010_0010
? This is another way Python 3 will make your life easier – optional underscores in numeric literals, which can help to make things more readable.
Unicode and Bytes
In Python 2 the concept of bytes and strings were pretty much interchangeable, and both came under the str
type. This led to some very nasty conversion consequences and unpredictable behaviour. The headline to remember is that in Python 3 all strings are unicode. A distinction was very deliberately created between text and bytes, offering a much more defined way of working.
In the below examples, we test the type of a bytestring, ‘normal’ string and unicode string in the interpreters of Python 2 and 3.
Python 2.7:
>>> type(b'foo') <type 'str'> # In Python 2, a bytestring is a normal string! >>> type('foo') <type 'str'> # The same bytes type as above >>> type(u'foo') <type 'unicode'>
Python 3.7:
>>> type(b'foo') <class 'bytes'> # In Python 3, this has its own bytes type >>> type('foo') <class 'str'> # In Python 3, 'str' means unicode >>> type(u'foo') <class 'str'> # It's a normal string
This means that dealing with encodings is much clearer in Python 3, even if it comes at the cost of slipping in a few more .encode()
s. Chances are that when your program communicates with anything in the outside world, such as files or sockets, you’ll have to encode and decode your data.
As an example, if you’re using pyserial
to read/write to a serial device, you’ll need to explicitly encode and decode your messages.
import serial PORT = '/dev/ttyACM0' BAUD = 115200 ENCODING = 'utf-8' if __name__ == '__main__': ser = serial.Serial(port=PORT, baudrate=BAUD) ser.write('hello'.encode(ENCODING)) response_bytes = ser.readline() response_str = response_bytes.decode(ENCODING)
String Formatting
Formatting strings in Python 2 was performed in a similar style to C:
author = "Guido van Rossum" date = 1989 foo = "%s started Python in %d" % (author, date) # Guido van Rossum started Python in 1989
The docs explicitly state that this way of formatting “exhibits a variety of quirks that lead to a number of common errors (such as failing to display tuples and dictionaries correctly)”. It’s also inflexible, and starts to become ugly to look at when dealing with long strings.
We now have two new ways of formatting strings. One is ultra-convenient, and one is ultra-powerful.
Formatted String Literals
Often referred to as ‘f-strings’, these provide an incredibly easy way to reference any variable available in the current scope.
Checkout how intuitive and readable this code is:
author = "Guido van Rossum" date = 1989 foo = f"{author} started Python in {date}" # Guido van Rossum started Python in 1989
Anything inside the curly braces will be evaluated as an expression, so you can put small logic or statements inside the string if you so desire. It’s probably not very readable to contain program logic within a string, but if it’s just getting logged to provide extra debug information then it’s really handy.
author = "Guido van Rossum" date = 1989 foo = f"{author.split()[0]} started Python {2000 - date} years before the turn of the century" # Guido started Python 11 years before the turn of the century
The .format Method
In Python 3, every string has a .format
method, which provides a dazzling array of options for formatting, covering the overwhelming majority of use cases. We won’t go into detail here as it is backported to 2.6 and 2.7, so won’t be a big upgrade pull for most Python 2 users.
Here’s one of our favourite guides for reference.
Imports
Let’s say that you’re using Python 2, and have the following file hierarchy:
pkg ├──service.py └──misc.py run.py utils.py
run.py
simply imports and calls something from the service
module in the pkg
package.
But service.py
relies on functions contained in utils.py
. So at the top of service.py
we have this statement.
import utils
Seems fairly unassuming, and everything will work just fine. But what if our folder structure now changes, with pkg
acquiring a new utils
module?
pkg ├──service.py ├──misc.py └──utils.py run.py utils.py
Time for confusion: our code now switches and uses the utils.py
file within pkg
. Things would get even more messy if we happened to have a library installed named utils
. This approach isn’t defined enough, and consistently led to unpredictable behaviour in Python 2.
Python 3 to the rescue: it’s no longer supported syntax if it’s ambiguous whether the import is supposed to be absolute or relative. The top of service.py
could become any of the following options depending on what’s required.
# To import from within pkg, either use relative from . import utils # or absolute from pkg import utils # To import from the same level as run.py, use absolute import utils
This feature might seem like a bit of a nicety in this example, but when dealing with big codebases containing large package/import hierarchies you’ll be glad of it.
Other
There are many, many other features which offer improvements and entirely new features over Python 2, even if some are only useful in niche areas. Here are just a few:
- The addition of the
asyncio
library makes writing asynchronous programs a breeze. A must in modern programming. - Other major standard library additions (like
concurrent.futures
,ipaddress
, andpathlib
) - Accessing a parent class in Python 2 is needlessly heavy on syntax. In Python 3,
super()
becomes even more magical. - Many builtins such as
zip()
,map()
, andfilter()
now return iterators instead of lists. In many cases, this will save significant amounts of memory without you even knowing.
Tools
If you decide that porting code from Python 2 to 3 is the way to go, there are some existing tools to make your life easier.
- 2to3 – the official automated code translation tool. Yes, it will port the code for you! Not guaranteed to catch everything, but does a lot of the tedious syntactic fiddling.
- caniusepython3 – a nifty utility for detecting which of your project dependencies are stopping you from making the leap.
- tox automates and streamlines the testing of Python code. It allows you to easily test your code on multiple versions of Python, which is fantastic for any project in general, but particularly comes in handy when you’re testing the success of your newly ported codebase on different versions.
Conclusion
There are countless reasons to upgrade to Python 3 – not just because of the convenience of new features, but because random, obscure bugs in the language get fixed regularly by Python developers, in Python 3 alone. Only the most robustly tested, never-need-to-change codebases have an excuse to remain at Python 2. Everything else should be enjoying the fantastic hard work put in by Python developers to make the language what it is today.
Just don’t use Google’s current Python course :)
https://developers.google.com/edu/python/introduction
“As mentioned on the setup page, this material covers Python 2. While we recommend “avoiding” Python 3 for now”
Note that this page on Google was: “Last updated August 5, 2016.”
Yes, and also note that this is Google. The same Google that once employed the creator of Python and uses Python heavily in e.g. their AI stuff (TensorFlow, etc.) Pretty embarrassing for their Python guide to state they recommend avoiding Python 3.
Hi from the Google Python Team: Thanks for pointing this out! I’m looking into getting this updated. Nobody should avoid Python 3 these days!
Note that this Python course is really from 2010 (see the associated videos) back when Python 2.7 was brand new and Python 3 was still being polished up and not well supported by anyone.
Thanks for updating!
The whole Python 2 vs 3 crap really made me uninterested in programming python, sure I used and still use lots of python dependent FOSS but I never made it “one of my languages” so to speak. Since the advent of Julia and Jupyter notebooks I’ve gotten much more interested and the fact they are working to kill off Python 2 has got me even more excited, finally its ready for prime time.
Install the Intel Python3.5 with their Math Kernel Library and Jupyter (included in the package) will run lickety-split.
I’d highly recommend using 3.6 or higher, there were some quite nice performance improvements that came with 3.6, so much so that many 2.7 diehards finally gave 3.6 the nod as ‘OK, I can’t justify not switching now’.
Significant whitespace is one of the dumbest things ever to be forced into a programming language.
Really? I love it.
It’s actually great. Because it forces people to write more readable code.
And again my mantra: use a bloody IDE,
it’s the same with all those morons complaining about how annoying C can be if you forget a ; somewhere…
The whitespace rules are simple, so everyone knows its a tab and not 5 spaces for example. I think using whitespace instead braces makes code easier to read and more consistent between coders.
If you don’t already program with significant whitespace, your code is a nightmare and no one wants to read it. Otherwise, requiring consistent indentation (the only requirement Python actually has) is not something to be afraid of.
I am not a python programmer (despite taking some quick online course on it); I found it to “deliberately break code from previous versions” a very bold move (for any language actually). But if it is for a good reason (to clean future code), I am all for it
Perhaps if the developers had focused on all of the distribution problems that plague python, instead of hypocritically nit-picking things like the usage of the print function, while simultaneously giving the raise function a pass, then people would have adopted it earlier.
The bottom line is that the developers went off on a tangent for a decade and now conversion of the population can only be done by evangelism, because the new features aren’t compelling enough to stand on their own merits.
I kinda agree with some points, and disagree with others. The division thing, though, was wrong from the beginning in the old versions ( any good language has float and integer divisions , so making something that would be thought as float divisioni return only integers was a bad move ) .
But the whole thing of breaking compatibility made me lose interest in the language. Wanting to run some little utility from the ´net and having to discover which “python version of the day” it needed and trying to install it brings no joy. Then later we don´t even know which version is running for default. They could have kept compatibility with old code in the newer versions, they just didn´t want to.
Any good language has Binary, end of. :)
Python is absolutely infuriating, almost as bad as ‘owt to do with Android.
“Python version of the day” is a bit hyperbolic, considering Python has only broken compatibility once, over a decade ago now. I guess the issue is coming up again because several Linux distros are just now making Python 3 their default Python.
I have used Python in the past and despite some nice features, I really cannot like a language that uses white space for block structuring, No doubt everyone will say use the IDE but the embedded system I was using it on didn’t have an IDE and insisted on compiling the code whenever you updated a source file, so you were screwed if your editor happened to use a different tabbing strategy to any code you were modifying (later versions did allow download of precompiled modules, which was an improvement since you could use an IDE on a PC or somesuch, but early development was fraught with danger). Of course. swapping a single tab for a space may no longer break the block structuring… I stopped using the language as soon as I didn’t have to work on that system any more.
No kidding! And along with 2.7 vs 3.0 issues that made WIndows DLL hell look positively pleasant, cryptic error reporting, playing “guess which way to install additional modules”, and being one of the single worst languages for performance, I’ll go out of my way to avoid ANYTHING to do with Python.
People thought Perl was painful, then along came Python to show them what pain truly was.
You said ‘Perl’, may you be forgiven…
I always hoped that there was a hell just so Larry Wall would know what he unleashed.
You take that back! Perl is a gift from Heaven.
! Most of these newer, lesser languages are simply Perl without some of the interesting “features”.
Once you know a few, this is obvious. I’m not fond of obscure regular expressions, but after Larry put them in,
all languages have them now. Who is leading the way, again?
In the case of python, they should just have called it a new name instead of the same one and breaking compatibility.
They could also have adopted “there’s more than one way to do it” and not pissed off everyone who hates
whitespace instead of brackets (which are far easier to bounce back and forth on in most editors).
Perl was making the same mistake, but I think perl 6 is pretty much known as Rakudo now, since it’s really not the same at all.
I find perl gives you enough rope to either tie up the mule and get a load hauled, or to shoot yourself in the foot.
I don’t blame the language for crappy self-impressed too-clever coders thinking obfuscated meaning is job security – you can do that in any language. Is there even one that DOESN’T have an obfuscated or golf contest?
Those kinda people should write bad poetry and die in obscurity.
Having had to at least borrow a lot of python lately (like device drivers for raspberry pi stuff) – perl’s Inline::Python compiles the python – and reveals tons of horrible python coding, particularly in drivers where it’s so easy to sleep n milliseconds, the writer never learned to check a ready bit. And you discover this in perl because, believe it or not, python runs faster inside perl! Personally, I like easier/better control of namespace pollution than you get in python.
But that’s a preference, not a life-death thing. I kinda like it that I have to specifically include something having to do with high precision timing right up front to warn readers that this kind of trickery is going on…
To repeat – it’s not the language. It’s the coders. The more accessible you make the language, the more dumb beginners and generally bad artisans jump on board. You’re not going to fix that anytime soon.
Every language I’ve seen in a long time watching that was going to “fix bad coding practice or make it impossible” has turnd out to have near-universal disdain in the end. Wonder why.
I mean, I think there’s something to be said for the sharp distinction between Perl’s “many ways to do it” and Python’s “one true way to do it”… most of the advantages / disadvantages fall out because of that split. Perl is (maybe) hard to maintain because everyone has their own style that still works and gets the job done. But it’s harder to hack something out quickly, and the resulting Python is (maybe) inelegant because the language forced you to fit your program to the designer’s whims, instead of the other way around. And so on.
The ecosystems are roughly on par IMO – CPAN is great, and I assume whatever Python uses is too (pip?) although the 2/3 split is the biggest headache there. “Batteries Included” is an interesting philosophy… but CPAN makes the batteries immediately at-hand so it’s not that big of a selling point. I do wish Local CPAN was more of a frontline support use case, a lot of people seem to balk at it when going to shared hosting and they can’t get their host to install some critical package.
End of the day, I learned Perl first so I’m familiar with it. I would hate to give up regex as a first-class language feature. And both languages are preferable to PHP and JavaScript :P
” I would hate to give up regex as a first-class language feature”.
Python supports regex with package ‘re’. So you don’t ‘lose’ that capability when writing a Python app.
https://docs.python.org/3/library/re.html
“one of the single worst languages for performance,” Not anymore. https://software.intel.com/en-us/distribution-for-python
C is one of the best languages for performance. You can easily write your own python libraries in C. If you don’t already know how to do this, you’re missing out on one of the best parts of the language.
One of the best parts of the language is how easy it is to use a different language?
Oops. didn’t mean to report the next post (tim), darn lack of editing here – hit the wrong link.
But yes, the ability to use one language inside another, or to use one to write another is kinda cool and can be super useful and time saving. Sometimes I have a big bunch of number shoveling to do == C is the choice. But I need to also interface with humans, text, databases, stuff like that – almost anything else saves programmer time. So more than one language is good, at least for the complex stuff I do.
What? Python is an incredibly performant language off the bat which is why it is the go to language for scientific work. Most people making such a claim have not the slightest idea what they’re talking about; it’s not just the performance potential that counts but the development efficiency and performance of built-in data structures. With Python you’re often at the “make it fast” stage before traditional languages even reach the “make it work” phase…
I was scrolling on mobile and accidentally hit report. Please disregard! I totally agree with the content of this comment. :)
Tabs are evil in any language, m’kay. The least they will do is screw up whoever maintains your code after you.
That’s what I fell foul of – my editor used spaces (because I set it to) and nearly everyone else thinks tabs are the way it should be done. I wouldn’t have minded if they could all agree on the amount of indentation, but some of the C code I had to maintain fired half the line up against the right side of the edit window :-)
Tabs are the best though, aren’t they. One key to add, one key to remove, great.
We’ll end using 1-space for indentation and editors that threat leading spaces as extra wide ones… :-Þ
Sure there will be an emacs minor mode for this soon… ;-D
The editor I used regarded the TAB key as an indent command and inserted virtual spaces that became concrete as soon as you typed something, so the one key to add isn’t really an issue. Once concrete it could delete white space up to the next character with a single key (mine was set to use shift/Del), so that wasn’t an issue either.
As I said originally, TAB is fine if everyone agrees on the indentation, otherwise it becomes a mess once several people with different ideas about indentation work on code.
However you cut it, using white space to define blocks is only going to work if you accept any white space and don’t terminate a block if someone inserts a line with different leading white space to that already in the block. Otherwise the only way to tell the block has terminated is to make white space visible so you can see the difference between the spaces and any TABS.
Just for reference (yes, I’m going to go there– engage flame-war shields), there are macros for emacs to do the space/tab conversion seamlessly and invisibly, pretty much any way you prefer, and have been since the 1980’s when decent location-addressable displays finally displaces teletypes, DecWriters, and punchcards. As I have always been between systems (thankfully, IBM 360/370 line is no longer in the list… If I never have to write another JCL deck, I will be quite content. If I never have to use EBCDIC again, I may achieve true inner joy) I have avoided tabs with a passion since maybe 1980, since tabs don’t move portability and mess up formatting between devices (sometimes within a device).
Before someone starts gabbling about non-fixed typefaces, note that all programming environs used fixed by default (some don’t allow non-fixed), and the typefaces for code display in most systems that are content aware are fixed.
If you like to code with tabs, more power to you, but I tend to find (as do many others) that two or three indents with tabs leave the option of exceptionally wide screen real estate or accepting that you will lose some on one side or the other, as well as deal with side-scrolling window. “Lines shouldn’t be that long” you say? “you should be breaking up into smaller functions if they are” you say? Um… no. Really. Try writing ANYTHING meaningful in Java without at least 5 indent levels (presuming you follow the Java style prescriptions). Using common 8-space indent, that’s 40 characters. This entry window is about 96 char wide (content dependent, but I just counted several lines), so 5 indents is almost half, and 6 is. Yes, some editors let you set the tab columns. This makes it worse when working with other people or moving between systems.
Yes, it is all about your preference, and I will work with tabs when I must, but prefer not. I can give a number of reasons tabs are preferable, as well, but, overall, IMHO, spaces rule and tabs drool\H\H\H\H\H\H\H\H\H\H\H\H\H\H\Hare preferable to tabs in virtually all cases.
What you say is correct, but incomplete. Not using whitespace to define blocks immediately imports treating impossible to read code as legitimate. While conversion of everything from tabs into spaces invisibly and automatically is something any editor can do, converting nightmarish brace-based formatting into well-formatted code is something no editor can do reliably, especially without breaking the future ability for sensible diff-ing.
And it imports the need for mentally opening/closing blocks while reading through the code as nothing but balancing the braces mentally can reliably account for them, a task unnecessary in code that mandates consistent indentation. Almost all sensible codebases would work perfectly fine if you stripped the braces and treated the indentation as indicative of block membership. Many large teams/codebases mandate exactly this by creating git checkin triggers that convert tabs to spaces and apply formatters or require such things before checkin can proceed. It’s just a matter of the braces being required too, at which point they’re really just superfluous.
No. Tabs are the RIGHT way to do things. The only reason tabs so often end up being a problem is because some jerks still insist on mixing in spaces or they set their editor to display tabs as spaces and then proceed to fill the code with multiple tabs per level of indentation.
Just use ONLY tabs for indentation and ONLY ONE per level of indentation. Then customize your editor’s settings to make it look good to YOUR eyes. Done! Now don’t mess it up!
Here’s the thing.. we each have different ways of seeing things and different preferences. I find 2 or 3 spaces to be just about right. It looks good to me and I easily see where the blocks are. Many people like 5 or 6 spaces. To them that works well. To me it is painful, all that right-left movement my eyes have to do to read such code is distracting and makes it harder to follow.
I’m not right. I’m not wrong. Neither are the others. Tabs combined with a good editor can accomodate us all. Spaces do nothing for this problem. Using spaces, if a wide-indent loving person is in charge.. well then F me. On the other hand if I am in charge (yet we are for some reason using spaces) well F the wide-indent lovers.
How backwards is that!
Just use spaces, configure your editors and everyone can be happy! Why would anyone be against that?!?!
The flaw in your argument is that it makes it virtually impossible to include tables or columated text. Now IF the editor was smart enough to use tabs up to the first non-white space character, then use spaces for ALL following text on the line, it would work. I’ve not seen any editors configured out of the box that work that way.
What?!?! I’m only talking about indentation. That IS exclusively the text to the left of the first non-white space character. Of course one should use spaces after that!
And what do you mean about editor configuration? Good editors let you pick how wide the tab character is on the display. Usually this is in terms of number of times the width of a space character. I like 2 or 3 space indents so I set my preference to 3 and visually, when reading code that is 1-tab character per level of indent what I see is exactly identical to what I would see if the code was typed with 3-space character indents. The beauty is that my coworker who prefers 7 space indents sets his preferences and he sees something visually identical to code that is type using 7 space characters for each level of indent.
It sounds like you are talking about the editor choosing for itself which whitespace character to use each time you press either the space bar or tab button. I’ve seen editors that do this to the indentation (the area before the first non-whitespace character). Mostly out of the box they ruin it by turning tabs into spaces. I’ve never seen one that takes your spaces that occur mid-text and turn them into tabs or vice versa!
^^ = 1 tab character for easy visualization because I don’t want to find out what wordpress does to actual escape codes in a non-editable comment, space characters are represented by actual spaces
class foo(){
^^string bar(){
^^^^/* A table in some comments
^^^^ In |Out |Total
^^^^ 1| 2| 3
^^^^ 1| 1| 2
^^^^ 3| 1| 4
^^^^ 1| 2| 3
^^^^ See, it isn’t that hard!
^^^^*/
^^^^return “Goodbye Cruel World!”;
^^}
}
If you can’t type that on your editor you need a new editor!
And if this looks messed up on your screen I blame the fact it is being viewed in html. It wouldn’t do that in a plain text editor.
Ugh! html ate my multiple spaces thus the table looks messed up! Not really a problem that’s applicable to writing/viewing source code though.
You must love Python, then, as the recommended indent is 3 spaces.
Not really. I recognize that my own preferences are not universal. I think they should recommend tabs so that we can each configure our text editors to give us our code our own way.
WTF? Recommended indention in Python is 4 blanks as per PEP8. BTW: 1 Tab == 8 blanks, that’s a nature constant like π…
You indent anyway, don’t you?
Python 3 doesn’t allow mixing leading spaces and tabs if it can disguise the intendation level.
Or even the indentation.
Why is it that images depicting the Python language always show a snake when a dead parrot would be more appropriate?
Or at least a foot:
https://upload.wikimedia.org/wikipedia/commons/d/d3/Python-Foot.png
I wonder how much developer time has been wasted because of the change to the print statement.
Not much. The real waste came for strings, bytes and exceptions.
Python 2 is still the default pre-install on, for example, OSX. If it came with v3 (or both) the switch would be a no-brainer. It is not nice if some simple script has to come with a list of “install this also” instructions.
Well it’s either install a library or reinvent the wheel every time someone wants to write a script to read a url or manipulate a matrix. You can get a lot of commonly used libraries all packaged together (Conda, anaconda, &c) but is it really that hard to type ‘pip install SomePackage’ ? How often are you really installing libraries?
My remark is about asking users the script installing a different Python version in the first place. So write for what is on their system already, and that is Python 2.
Isn’t it fairly standard for the OSS bits and pieces OSX includes to be relatively ancient?
My impression from when administering some was part of my job was that(unlike your average awful embedded widget) Apple at least considered what it did ship as something it had responsibility for; so you usually didn’t get ancient versions and ancient vulnerabilities; but that you could pretty much just use macports or fink if you wanted a vaguely recent OSS userland experience; while Apple only really cared about their languages in terms of enthusiastic updating(so Objective C and Swift; updates available except for older OSX versions that Apple would prefer you upgrade; but much more limited first-party support for python and others).
https://www.youtube.com/watch?v=o9pEzgHorH0
I’ll never understand why people reply with a 27 minute video with no original thought appended to it, or at least a single line TL;DW.
Because the title “Stop writing classes” is the TL:DW and the video clarifies it better than I could. The first 10 minutes does a good job elaborating with the remaining 17 minutes offering better solutions to classes that don’t do anything and redundantly named exceptions.
You may not have 27 minutes to watch the video but if you use python these 27 minutes might save you from falling into the anti-patterns it addresses, so you might want to find 27 minutes to watch it. If you don’t use python, then this comment isn’t aimed at you.
“Stop Writing Classes” is a complete nonsequitur.
“stop using classes” just translates to another reason to avoid python all-together, what a terrible language.
If I had to use Python I’d stop writing classes too. Fortunately I can get away using OOP languages instead (most of the time).
Python works just fine using OOP.
The talk doesn’t say you should never write a class, the speaker just implores you to “stop writing [bad] classes”. Writing Classes like the example code in the article is the type of class you shouldn’t write.
Class InvalidSalaryError(Exception):
pass
or
Class foo:
def __init__:
a = none
def Do_Something():
spam = a + 5
These just clutter up your code base making management difficult for anyone else or yourself in 6 months when you forget what these lines do but you’ve imported them in the rest of your projects.
These classes don’t do anything that couldn’t be written in 2-3 lines of stand alone code that’s more readable but rather than have me transcribe the talk, just listen to what the speaker has to say. You wouldn’t write C like you do perl so why do people keep trying to write python like C / java?
I swear this is because they changed the print function. Every beginner saw that the most basic thing had changed to be longer and said “nope”, and the community is still feeling the effects today.
They decided to be religious (“one way to do it”), instead of thinking about the users.
If that were entirely true, raise would also be a function. I’m just not sure whether to call it inconsistency or hypocrisy.
Maybe they should have gone Full Perl and made parens optional :P
Python 2 uses “raw_input(…)” when getting input from users while Python 3 uses “get_input.” A pain to remember!
.decode(‘hex’) was awesome though, and the fact that binascii.hexlify(bytes) -> bytes doesn’t make it better.
PEP: Add a hidden easter egg that scans the system for python 2 packages and code and deletes them 1:st january 2020.
maybe you should look up the definition for the word easter egg..
Alright. Scan the system for python 2 packages and code and delete them on Sunday April 12, 2020. Better?
And what happens when Python 4 comes out? All Python 3 afficionados will realize that breaking compatibility *once* meant that *they* are now in for a rude awakening.
Breaking compatibility when you need to is a good thing, if you don’t get rid of the trash it ends up being all you have. Having upgrade routes would be the best, but it’s very difficult, maybe something more like a staged deprecation like Java could have worked better, but that takes years and many versions.
Maybe, maybe not.
But sometimes breaking compatibility make totally sense. Imagine a world where C++ code isn’t infested with old hacky C.
Most people failed to adopt Python 3 for a reason not addressed here. Some library they used (i.e. Numpy, Pandas, PIL, …) hadn’t yet been ported over from 2 to 3. I do believe most (if not all) of the examples I listed above have been ported over, but it took a long time for a lot of libraries to be ported over. That lag discouraged a lot of people (including myself) from switching over.
Now my only excuse is that my fingers don’t want to transition to Print as a function instead of a keyword…
THIS RIGHT HERE.
I work in Python a lot, and the 2 to 3 transition– the items (nicely!) laid out in the article– is not a big deal at all.
The holdup was all about package compatibility. Python3 is so, so much better.
As for “I don’t like formatting with indentation,” um, well, I don’t like mustard, but I don’t generally like vinaigrette made without it either. We must not be dogmatic.
I started with Python 3, but after frustration with libraries I needed only being available in 2, I switched. I’ve used Python 2.7 for the last five or so. But a few weeks ago Julia 1.0 was released and I’m hooked! https://julialang.org/
My department in our company started with Python 3.3 (moving to 3.6 shortly) to solve a headache for us. Therefore we don’t have any conversion problems. That said I don’t really understand some of the comments above, because Python is very easy to read, write, and use and just about any add on module you could think of. But, as with any language, you can make it as obtuse or hard to use as you want. We have standardized on Python for our use ‘when applicable’ for its ‘power in simplicity’ syntax and ease of maintenance. As an example, in one of our systems, we had a bunch of batch files, excel/db VB apps (yikes!), Perl apps, C# apps that all had to work in concert being called from the Windows Scheduler. A nightmare to figure out the rabbit trail of who did what where when you had track down an issue. Over the past years, they have all been replaced with Python. Each program does everything it needs to do (not spread out over x number of apps). Working out very well for us. Easy to go check on a process. Call outs (called back to the office anytime of the day) are just about non-existent on that system now. And when there are our it usually turns out it wasn’t our problem (say someone else’s sftp site was down is why the data wasn’t flowing). And if a change needs to be made, it can be made on the fly, on the system that has the problem. No need to have a compiler handy or compile on development machine and then ‘re-deploy’ the app.
I don’t allow tabs in our code base (C/C++, Python mostly) . All tabs do is mess up the code and cause headaches down the road for someone else. In C/C++ you ‘really’ see this very aggravating problem when trying to make sense of someone else’s code. Spaces work very well. Tabs should be ‘outlawed’ (or the editor set to tabs replaced with spaces).
The ‘pip’ install process makes it easy to get most modules that we need taking care of dependencies for you.
Since we use Windows… I can copy the ‘python folder’ (all set up with needed modules) to any machine, any drive, and Python is ready to be used there. Another plus for us.
Code blocks should be lined up for readability, and Python forces this which is a good thing.
As an object oriented language, I like it’s simplicity. We don’t go out of our way to use the most hard to understand constructs in Python. We keep it simple, even if it uses a bit more code or is a bit slower. In the back of our minds is someone else down the road will need to maintain this code and he/she may not be a trained programmer.
I do wish it was strongly typed, but there is always some down-side to any language.
These are just my thoughts though from years of coding!
Python is strongly typed.
Open up an interpreter and try 1+’1′. Java will coerce it behind the scenes to give you 2 but python will throw an exception.
I believe you are talking about statically typed which no interpreted language does by definition. I don’t understand the fixation of static v dynamic typing, they do the same job you just get your errors at different times. Keeping track of what data types your using isn’t that difficult, is it?
As for speed there are lots of things you can do to speed it up using pure python or you can use libraries written in fortran / C (NumPy). Most bottle necks are due to people trying to code python like they code C++ or java. There’s a pythonic way to do things and it’s generally faster than transcribing other language grammar into python words. When speed really matters you can write in cython, intersperse faster languages into your python code (fortran-magic one such library), write a C extension, or just switch to the faster language for that whole project.
Type manipulation exploits are common, so I say yes being sure what type your program will be using is hard.
Yes. Adding in tabs when the rest of the code uses spaces does cause problems. That is why ALL of the indenting should be converted to tabs and every time someone is caught using a space they should have another finger broken!
Tabs work great when you don’t try to mix them with spaces. Use 1 and exactly 1 tab per level of indent. You can configure your editor to display that tab as exactly the number of spaces that per/indentation looks good to you. And.. you coworkers can configure their editors as for what looks good to them.
Spaces are for people who just want to force the indentation that looks good to their eyes on others. It makes the code harder to read for people who don’t see things the same as yourself.
> Adding in tabs when the rest of the code uses spaces does cause problems.
Only if you mess with the meaning of the natural constant “tab”. It’s the same as saying chillies in the hand cause troubles because you once handled them with an open cut…
> Spaces are for people who just want to force the indentation that looks good to their eyes on others. It makes the code harder to read for people who don’t see things the same as yourself.
Right, that’s a completely different topic from brace placement in other languages …
I already have seen code which runs faster on Python 2 than on Python 3. But PyPy was even faster. ;-)
But I agree that there is no need to write Python 2 only code, even if Python 3 features are not needed, especially that usually Python 3 code runs on Python 2 without any modifications.
There is a small regression:
def display_image(name, (x, y), mask):
#…
is valid Python 2 code whereas there is no automatic parameter unpacking in Python 3. (It’s called “automatic tuple unpacking” but I don’t know where else it is relevant—apart from assignment which -fortunately- did not break.)
From time to time, programming language developers do this, and it is morally indefensible, but perfectly in their right.
Inform, a language for interactive fiction, went from C-like to natural language. A more extreme change than Python, No inform 7 code will run in Inform 6, but Python 2 and 3 are still essentially different dialects, & maybe they’d be better off if the developers didn’t try to gloss it over, and embraced that they aren’t the same.
Declare a new language instead of abusing version numbers to mooch off the glory of a language that will be simultaneously derided.
For those really worried about Python2/3 and compatibility there is a library for that. Write once and run on both! http://python-future.org/index.html
Also, if you’d like a little functional programming in your Python there is coconut which also happens to solve the 2 vs. 3 issue. http://coconut-lang.org/
As for me, I’ve moved on to Perl6 and am having more fun solving programming than I’ve had in a long long time. Runs on Raspberry Pi, too!
I think those print examples are not quite equivalent. They do print the same output but I think you should write the example of Python 2 syntax’s equivalent in Python 3 like this:
print(“Fresh Hacks Every Day”)
print(“Foo”, “some more text on the same line as foo”)
or the example of Python 3 syntax’s equivalent in Python 2 like this:
print “Fresh Hacks Every Day”
print “Foo”,
print “some more text on the same line as foo”
So maybe just one a bit longer example:
Python 2’s syntax:
print “Fresh Hacks Every Day”
print “Foo”, “some more”,
print ” text on the same line as foo”
Python 3’s syntax:
print(“Fresh Hacks Every Day”)
print(“Foo”, “some more”, end=”)
print(” text on the same line as foo”)
Also sep and file arguments are useful sometimes. I learned the Python 3 way and always import print_function from __future__ if I need Python 2 compatibility. That solves the most of the compatibility issues with print. Six solves the rest. Well, writing Python 2 and Python 3 compatible code should be for another blog post. Also sometimes you don’t want to stay compatible with Python 2 just because it would make things harder (missing libraries for example). I advise to write for Python 3, and if you need Python 2, then make it compatible, but remember to check first that your requirements work with both.
A year ago I had a professor that insisted we use Python 2.7 because he was switching until more libraries were available in Python3. I TA’ed his class in the spring and he insisted folks use Python 3. Major switch for him just that fast. As a practical matter, there is not that much difference. Just be aware of the differences and code accordingly.
For folks that avoided learning Python because of the switch, you are missing out. One of the speakers at PyCon 2018 (and I do not remember who at the moment) had a great description of the language: “Python is the second best language to do anything.”
Really good summary, thank you for sharing.
All the people in this thread complaining about Python breaking backwards compatibility, once in 25 years, are probably the same people who bitch endlessly about how C++ is saddled with warts because of backwards compatibility.
print is better as a keyword. Change my mind.
I want to capture prints and redirect them somewhere else. How do I redefine a language keyword?
You don’t redefine a language keyword.
temp = sys.stdout
sys.stdout =
print “foo”
print “bar”
sys.stdout = temp
That is a bit ugly, so you wrap it in a function or a context handler.
I dread to think how many people have been lost from the language for good after being subjected to the weeping sore resulting from trying to run other peoples code on a system which requires both versions to be always present and lacks a well defined way of reliably keeping versions in their respective box. The transition hacks work if you have control over the situation but rapidly fail if the black box program is in control of the system. It would have been far better to give the language a new name so that there was no doubt about the required support libaries for the version in use at any time. We, like many others, invested a lot of time in what appeared to be an elegant language and it has driven us nuts.
Maybe not “lost from the language”, but I can assure that my opinion of the language get much worse after just trying to run a simple piece of code and having to deal with that version problem. Just starting the .py file with a line specifying which version it uses, and then having the interpreter running the correct code branch would have kept it easier and compatible for much more people.
And the developers could have focused on adding things, not just changing things.
If Python3 would fully support HP-UX I’d make the jump in a heartbeat. As it is, I’m stuck on 2.7 as our cross platform scripting language.
HP-UX? I didn’t realize that was still a thing. Last time I used that was on HP Apollo 9000 workstations 20 years ago.
Yep, it’s still a thing in some shops. We’re making the jump to linux fairly quickly, but there are still a lot of HP-UX systems in use.
I’ll have to eat my words. I was able to get Python 3.7.0 built this morning on HP-UX 11.31.
Hello foobarlabs, we also have several hp-ux 11.31 servers, were did you get the 3.7.0 python distribution ?
Stop using python learn a real language like Klingon
Just wait out for Python 4 probably would not be compatible with 2 and 3 so no use learning it now. :7
A big problem is that some newer Python releases, at least for Windows, rely on functions in the operating system that are not present in older O/S versions, like XP, Vista or even Windows 7.
Also when compiled with newer Microsoft tools, some external libraries gets incompatible with older O/S versions (probably because Microsoft want it to be that way).
To make a universal and useful programming platform you should ban all developing tools that sets limits to backward compatibility that have no technical reason (but mainly a strategic).
It is very frustrating to get a message from Windows that the program is trying to call a function (often basic file-handling functions) in some DLL that isn’t present because some lazy programmer didn’t bother to even try to make it backward compatible.
(And please don’t give me the usual you-should-have upgraded-a-long-time-ago rant. Those who still use older O/S versions, like XP, probably have good reasons why they do.)
How about just stop using python? ffs. /smh
No one ever wants to pay for infrastructure. Rewriting what is currently working is an expense that businesses won’t incur. Its like asking someone to rewrap their one ply toilet paper to be two ply. Ain’t nobody got time for that.
All you have to do is be lazy make a new program that determines which python version to use (I would add a header for the new version) and launches the appropriate one.
Make a bracket that holds two rolls wrap the bottom one over and upper one under, pull from the center.
Blegh, reading this article just makes me dislike python even more, i get how half the examples are from an old version the article specifically states to not use anymore, but by god thats some super terrible code, and the ‘new’ version really isnt that much better? i totally get how ‘some flavor of C’ can be daunting to new programmers, but by god, teaching them this tripe doesn’t help anyone, if anything it makes it harder for them to move on to a more powerful / less weird language? And yes, i totally get how good indentation is important, but making it a mandatory thing is just terrible design of the highest order.
Im sorry at all python folks i just disrespected, but yea, wow this language is shit…..
I wish the guy behind python stepped down years ago and the project already faded into obscurity, lets just hope that happens soon now that he did leave.
I am sorry too. Sorry you feel that way. I found Python 3 to be a very easy and powerful language to come up to speed on. Not hard on the eyes (if written with that in mind of course). Forcing the indentation is a good thing. I mean, it is something we learned by experience years and years ago, but some seem to write code which is like looking at a spaghetti pile (tabs and all). At least Python forces some sane structure to the code. A block is lined up as it should be. Then there is objects. The object (classes) concept is way easier to use than in C++ in my experience. Try it, you may actually like it!
As someone who does not use Python a lot. my biggest bugbear was how Python 3 broke compatibility with Python packages. I tried writing some Python 3 a few years ago, and I got in a hell of a mess with library incompatibilities.
OK, things are probably better now, but there are still some packages out there which are not compatible.
The other issue is most training is still in Python 2. So the question is, is there any feature in Python 3, which makes it a must upgrade? If not there are benefits in sticking with the largest common denominator of Python 2
STOP using python You use RUBY !
Python 2: Where true=false is a valid statement that will make your program do all kinds of fun stuff. Yes, you can re-assign keywords in Python 2.
My favorite Python 3.6 feature is the ability to unpack a dict in declaring another dict. For example:
new_dict = {**dict1, **dict2}
I only started to learn Python 3 after 3.6 had come out and this was just such a natural way of doing things that I hadn’t even realized it was a brand-new feature!
Looks like the code samples in the article got double-escaped at some point. There are a lot of “& quot ;”s and “& lt ;”s and such all over the place.