Is Python stupid, or is it me?
I am not, by preference, a Python programmer.
Every time I have to interact with it, I am reminded why.
I can do Perl; I can do PHP; I can do Bash, SQL, C and I used to do Fortran. I can even cope with whatever the Asterisk Dialplan Configuration language is called, but Python just finds novel ways of making me look stupid.
For example: '
import
I recently had the misfortune to get involved in a project based around Microsoft Azure Service Buses, and I needed to write a simple application to write to them, and read from them.
The best compromise I could find between a programming language I can use and a language which has Azure Service Bus libraries was Python. With a bit of help from the .NET guy who created the service buses in the first place, I pretty soon had a very simple program which could read and write from/to the Service Buses.
Hooray.
Next I needed to deal with the data I read from the bus, and that data is in JSON format.
I found out that Python has built-in JSON support; you just need to "import json" at the top of your program and you then have all sorts of helpful functions for parsing, packing, unpacking and generally fiddling with JSON data.
So, I put the Azure Service Buses to one side for a moment and decided to write a tiny program to learn how to work with JSON in Python:
- json.py
#!/usr/bin/python import json jsonstring="Hello." print jsonstring
(Yes, I know that "Hello." isn't a valid JSON string, but I'm just trying to start from something really simple here. You can imagine I called the variable gstring instead of jsonstring if it helps you focus on the point.)
What does this do?
It prints "Hello." twice:
$ ./json.py Hello. Hello.
Why?
Because I decided that json.py was a sensible name for a Python program in which I would play with some JSON.
Oh, no…
What does the Python interpreter do with that?
It imports the source code of this program itself, runs it and then runs the program. Hence you get twice the output you expected.
Okay, it didn't take me long to find other people on the Internet who've run into this daft behaviour, so I renamed json.py to notjson.py and ran it again:
$ mv json.py notjson.py $ ./notjson.py Hello. Hello.
Eh???
What this turned out to be was the Python interpreter having decided it was actually a compiler on one of my previous attempts to get this working, and producing a json.pyc file for me (I did nothing to ask it to do this).
notjson.py then imports json.pyc and I'm back to square one.
Can we fix this?
$ rm json.pyc $ ./notjson.py Hello.
Thank you.
Now I can get on with parsing some data and trying to cope with the bloody ridiculous indentation rules Python has.
For the same project as above, one of the first things I did while trying to subscribe to the Azure Service Bus and get messages from it was to display them on the console as they arrived. That at least gave me the confidence that I was getting them, and I could then get on with processing them (in JSON, see above).
So:
#!/usr/bin/python from azure.servicebus import SubscriptionClient recv_client = SubscriptionClient.from_connection_string('Endpoint=MyEndpointURL;SharedAccessKeyName=TheKeyName;SharedAccessKey=VerySecretKey', topic='MyTopicName', name='MySubscriptionName') msgs = recv_client.get_receiver() for msg in msgs: if msg.body is not None: print(msg) msg.complete()
That seems nice and simple, and it works.
Very slowly.
I knew that messages were appearing on the Service Bus at least every five minutes; more frequently when there was some activity in the background system.
My Python program was often showing messages 20 minutes or so after they happened.
Hm, I must have something wrong with my Bus listener process (after all, this is the first time I've done anything with Azure Service Buses).
As part of debugging this, I added a
print(datetime.datetime.now())
line in the loop, and I found out that the messages were being received about 0.3 to 0.7 seconds after they were being generated some way back inside the application.
They just weren't appearing on the screen for another 20 minutes or so.
Why? Because Python, in its infinite wisdom, thinks that when you say print you don't actually mean "display this on the console", but instead you mean "put this in a buffer somewhere and then show it on the screen whenever the buffer gets full".
Adding
sys.stdout.flush()
at the end of the loop made everything a lot more sensible.
Why?
I know that Python isn't the only programming language where stdout is buffered by default, but why?
What makes language developers think that programmers normally want stdout to be buffered - what's the point?
If programmers do not normally want stdout to be buffered, then why is that the default?
Go up
Return to main index.