Python vs. Other Languages

For the last two months or so my fellow McLane Advanced Technologies Programmers and I decided to take on Python. We all have pluralsight accounts so we decided to engage in the Python Fundamentals course by Bingham and Smallshire. It took us a couple of months to get through the course since we only would do it through our lunch hour. With schedule conflicts, practice exercises it took us a while to get through the course but we finally completed it a couple of weeks ago. And I must say, it was an amazing course. The crazy part about the course is that it's only 5 hours long. Five hours plus another 10 hours of hands on practice and you can be pretty decent at python.

Throughout the course we took time on our own to do some exercises after each of the lessons. I fiddled around with it quite a bit and decided to save my practice exercises to github.com (https://github.com/fernandozamoraj/py_sandbox). Although our goal is to go deeper with the sequel to this course, Python Beyond the Basics by Bingham and Smallshire, I want to list a few important lessons about python.

Python has a term called "Pythonic" to indicate the Python Way

Python is easy to learn. Any seasoned programmer can come to Python and learn it well enough in a matter of hours. However, Pythons capabilities and syntax call for a certain way of doing things. What I mean by that is the way you do something in one language, although it can be, should not necessarily be directly translated into python. This concept differentiates the hacker or beginner from the fluent programmer. One example that comes to mind is the typical swap of values like one does in sort routine. For example. In most languages (Java, C#, etc) you do a swap like this:


temp = mycollection[i];
mycollection[i] = mycollection[j]
mycollection[j] = temp

In python you can do the same thing like this

mycollection[i], mycollection[j] = mycollection[j], mycollection[i]

This is possible in python due to tuple inference. Python automatically treats these type of assignments as tuples. So it takes the first value on the right of the equals sign and assigns to the first variable on the left side of the equals sign. It does this also for the second variable and value. While you can translate how it's done other languages directly to Python, it would be considered unPythonic. You can learn more about the term Pythonic at http://blog.startifact.com/posts/older/what-is-pythonic.html. There is also a good video on youtube about becoming "fluent" in the Python language at https://youtu.be/E88m_uQxt1g. Python has many capabilities that other languages don't have and therefore you shouldn't necessarily translate how you do one thing in another language to Python. Some of these features at the root cause are:
Python Has Programming Standards

I've never seen any such thing in other languages. In other languages the guidelines are usually de facto standards but they are not necessarily written anywhere by a solid authority. In Python they are in black and white at https://www.python.org/dev/peps/pep-0008/. These guidelines provide an easy reference for all Python programmers to share.

 This has several advantages. One being that they can be readily adapted by any programmer team. Also, since they are widely accepted it helps all Python programmers to read each others code.

Python Has Specific Programming Principles AKA The Zen of Python 

The Zen of Python aka PEP 20. Again I have never seen this in other programming languages. Although some widely accepted principles do exist such as SOLID.

Python Is Dynamic

Python is a dynamic language which brings along the advantages and disadvantages of a dynamic language. Those advantages will force the developer coming from a static language to think and code differently. A programmer must also take certain precautions in order to overcome redefinition of methods and attributes. This can lead to some frustration for the static language programmer in finding obscure run-time bugs. This means unit testing much more important at least from the perspective of exercising your code. Unit testing is important period, but in the case of Python an un-exercised path might give a nasty run-time surprise. For example, you may discover that type has not been initialized before being used or that a method does not exist. These types of errors are caught the compiler, in a static language, but only until run-time in python. A simple typo would look fine until run time.

Classes in Python Are Totally Different than .Net/Java

Python's classes make every attribute and method public, period. Not by default, just period. There is no protected, private and public accessors. Python's guidelines indicate that you should code your fields a certain way if you intend them to be "private". For instance the field/attribute _first_name in the class Student would be considered private, because it starts with an underscore, and not be modified by external access. So in essence encapsulation in Python is a guideline not a rule.

All of a classes methods are static

Take the following code for example

class Student:
    def set_name(self, name):
        self.name = name
    def say_name(self):
        print(self.name)
    def log(message):
        print(message)

    def foo():
        #...do something

s = Student()

s.set_name("joe")
s.say_name()

This code is the same as the following
s = student()

Student.set_name(s, "joe")
Student.say_name(s)

You would think that the second example is using a static method and the first is using the instance method. In fact they are both using the static version. However the one that appears to be instance is only syntactic sugar and is actually doing what the second approach is doing behind the scenes. Another point to notice is the "self" variable. Coming from another language you might think that the word self has special meaning, and it does but only by convention. There is no "this" in Python classes. Self is not equivalent to "this" in that regard. It does represent the object in a sense but it could be named anything else. That is why it is always passed to "instance methods". If it is not passed the class cannot see it, unlike traditional Object Oriented classes, self is not available unless it is passed in to the function/method that needs it.

Take the following code for example;

s = Student()

s.log() 
s.foo()

In the above code s.log will work, but what will it print? It will print the s (Student) object. The calls
that is essentially made is

Student.log(s)

So you see, "self' has no special meaning. The second call s.foo() will result in a run time exception because the call that will be made is Student.foo(s), passing s as the first parameter but Sudent.foo does not accept any parameters.

Inheritance

Inheritance is another big one. In Python inheritance is usually use for re-using code but not for its polymorphic capability. Take the following example:
class Faculty:
    def set_name(self, name)
        self.name = name

class Student:
    def set_name(self, name)
        self.name = name

def foo(college_member, name):
    college_member.set_name(name)

member = Faculty()

set_name(member, "Joe")

member = Student()

set_name(member, "Mary")

The above code is an example of duck typing, something very common in dynamic languages. Since the call foo call is not resolved until run time, it can work on two different types as long as they implement that interface. More differences exist in classes between Python other classy languages but these are the ones that really stand out. I've noticed quite a few differences regarding the nuances of Python. Many of the nuanses can be explained in detail in other posts or even in the Python online documentation. My intent with this post it to show those C#/Java programmers with a curiosity about Python, some significant differences that are not readily apparent.

Comments

Derek Greer said…
Good article, Fernando.

Popular posts from this blog

Why I Hate Regular Expressions

Simple Example of Using Pipes with C#

Why a Programmer Must Have Sales Skills