What's wrong with Python

7. joulukuuta 2012 - 11.08

There are lot of sites listing the faults of PHP (e.g. PHP Sadness). Although I really really like PHP I cannot deny it's problems (which mostly inherit from the 90's and should be fixed ASAP). Yet, PHP is definitely not the only language to have some "strange behaviour". Java, C/C++ and Python are not without problems either. Even though I have done most of my programming with PHP I have also done some little things with Python. And here are my thoughts about the language. I have to mention that it is quite perfect for the beginners and it can be used to perform advanced tasks, too. Python is also a multiparadigm language, so one can write procedural, object-oriented or functional code if he/she wants. As Python is a high-level programming language, one can develop software very fast and the language is also available on many different platfoms. (Btw. If I was to teach CS1 and Python wouldn't be an option, I would definitely choose JavaScript as it and its derivatives are probably the most important languages in software development nowadays. And basically you don't need to install anything as a browser is the only thing required.)

But Python. I was here to talk about Python, right. So it's kinda good language? Yes. Perfect? No. Here are some things I still don't understand in Python.

Python does many things automatically to help the programmer (as does PHP, too). But with Python 2 you could, for example, try to calculate 7/2. What would be the answer? Yes, three. Python wasn't in the mood to help the programmer, but to give an integer when the actual result would be float. You would need to manually modify the number to float to get a float result. So 7.0 / 2 gives you 3.5. Thank God this thing was improved with Python 3. Why was it wrong in the first place? I understand the "problem" in C or C++, but with Python... It should help the programmer - not to confuse him.

Have you ever programmed with some other language than Python? You know that there are cases where you want to add one to some variable? You usually just write variable++ and that's all. With Python you only get SyntaxError. To ease the job of the programmer, you have to modify basic i++ line to i += 1. Is the latter better? How is it better? Why cannot Python let me use the widely used easier way??? I know that Python is the language where i++ is "not used, because you don't need it anywhere", but still. Someone might want to use it. Just like some of us prefer to use dictionary whereas others might prefer lists and classes.

So there are floats, integers, lists, classes and dictionaries in Python. What about comparing them? Let's consider this crazy scenario where we would like to compare integer and list. 100% absurd, but completely ok with Python 2.

>>> i = 3

>>> a = []

>>> a > i

True

>>> i > a

False

>>> a = [3, 5]

>>> i < a

True

>>> a < i

False

>>> 

So, in the first scenario integer is less than an empty list. The same happens with an assigned list. Let's check another example.

>>> l = []

>>> s = ""

>>> l < s

True

>>> s < l

False

So, this means that... err... String is greater than list. Why is that? Well, because L is before S in alphabet. Yeeeeeeeah! The most logical and intuitive choice there is. Well played. Once again Python 3 is much better and this kind of comparison produces TypeError.

Let's talk about string methods. We have methods like find, index and isdigit. What would the following return?

>>> s = "foobar"

>>> s.find("baz")

It returns -1 as the string "baz" is not found. What about another example.

>>> s.isdigit()

Yes, it returns also... no. It returns false. Not -1, but false. Strange... But hey! We can always use index!

>>> s.index("baz")

Which is exactly like find, but it returns ValueError instead of -1 (or false), when needle is not found. Three methods, three completely different return values, when needle is not found. Damn, it's easy.

Strings have even more methods. For example s.isdigit() returns whether the string is numeral or not (true/false). And when you want to know how long the string is you just write s.lenght()... oops, that does not exists. You need to use a function for that. len(s) gives you the correct answer. Sad, but true. In this case I really miss Java.

Then data structures. Let's first define two functions:

def f1(i):

    i += 1

def f2(l):

    l.append(1)

And then let's use them.

>>> ii = 2

>>> f1(ii)

>>> ll = [2]

>>> f2(ll)

What would be the values of ii and ll now? If we have been programming with C or C++, we would definitely guess that they would not change, but with Python the function with an integer parameter only gets a copy, but with list the function gets a reference. So the output is:

>>> ii

2

>>> ll

[2, 1]

Was this the case with Java, too? I don't remember anymore. But ok, so data structures are passed on as references. I can live with that. It's actually a good way. No problem. I just have to know it. How can I add data to my data structure? With a list like this:

>>> a = []

>>> a.append(1)

>>> a

[1]

>>> a[1] = 2

IndexError

>>> a[0] = 2

>>> a

[2]

So the append method resizes the list and after that we can manipulate it with the []-operator. Sounds a bit stiff. What about dictionary?

>>> d = {}

>>> d[0] = 1

>>> d[1] = 2

>>> d

{0: 1, 1: 2}

>>> d.append(1)

AttributeError

So with dictionary we can use data sructure more loosely, but not in the same way. NOT IN THE SAME WAY! We need to learn not to use append. Have you ever used e.g. C++ STL? Different data sructures have very similar interfaces - easy to learn, easy to use. What about removing an item?

>>> a.pop(0)

2

>>> a

[]

>>> d.pop(0)

1

>>> d

{1: 2}

Wow! We have a nice interface that works in the same way with both data structures. Damn, this is just how it should be. But is there something more? Yes... There is del.

>>> a.append(7)

>>> a

[7]

>>> del a[0]

>>> a

[]

This works also with dictionary. So, if you hate object-oriented programming, you can always use del statement. How can you add an item to a list without append? I think you can't. With del you can also remove slices from a list. Why can't you do this with some method? Use method to add (, but not with dictionary!), use statement to delete. As clear as hell.

What about rounding?

>>> f = 2.5

>>> f

2.5

>>> round(f)

2

Yes, you read it correctly, but this doesn't mean that Python rounds always just taking the decimal part out.

>>> f = 2.6

>>> f2 = 3.5

>>> round(f)

3

>>> round(f2)

4

Python has implemented the "bankers' rounding" which rounds a half to even. I think this is good, so it should not be even in this blog post? No, it should not. It's just one thing that Python does differently.

Then there is this object-oriented way of doing things. Let's define a class with an attribute.

class Cc:

    foo = "baz"

c = Cc()

print(c.foo)

So we can access its attribute. One of the corner stones of object-oriented programming is data hiding. Let's make the attribute private.

class Cc:

    __foo = "baz"

c = Cc()

print(c.__foo)

AttributeError

Now we got an attribute error, but we can still access the private part if we want to.

print(c._Cc__foo)

I like OO ways and this is not the best way to handle things (according to me). But this is the Python way. Someone put it nicely in the Internet:

"Python does not need to protect anyone from assigning a value to a member variable, because:

A) In Python you cannot accidentally make a typo such that a comparison turns into an assignment.
B) Python developers do not make mistakes.
C) All of the above.
D) What was the question again?"

Who am I to complain?

The last thing I want to point out is the use of colon. Why do we need to use it? In most of the cases with Python you write one thing, one line. That's why there is no ; after variable assign. So why do we need to put a colon after a class name, function definition or while loop? Could it be handled by a new line? Just wondering.

In a summary: Python is a great language, but I prefer something else - at least for now.

Lisää uusi kommentti