melp.nl

< Return to main page

Python: an introduction for PHP (and other) programmers

I love Python. It is clean, it simple and it evolves in a natural and healthy way. I have been working with PHP for over 10 years now, but Python stole my heart. Ahhhww :P

Here are some pointers to get you started, and hopefully make you enthusiastic too. Of course this is just a little tip of the iceberg. I can't give you a course in Python, but it should give you the push to explore a bit further.

Please note that this tutorial is primarily targeted at Python 21, but the examples all should work in Python 3 without trouble.

The interpreter

Before telling more about the language, you should know that the python interpreter has a great interface for use in the shell. You can type in statements, which are interpreted on the fly. Results of evaluations are printed to stdout, so you can see the result directly:

#!shell
$ python
>>> 1
1
>>> type(1)
<type 'int'>

To var_dump an object as in PHP, Python has a non-recurring variant dir(), which will show you all properties an object has.

#!shell
>>> dir(1)
['__abs__', ..., '__xor__']

Here you can see 1 has all the methods that are defined in the int type. 1 is, in fact, an instance of the int type, with value 1:

#!shell
>>> (1).__str__() # __str__ is equivalent to PHP's __toString()
'1'

It is useful to know throughout this post that every name in python is in fact an object, whether it is a constant, a literal, an object, class, function, or type. This is similar to JavaScript, which you might be familiar with.

Code structure

Structure is based on indentation. This means that you will no longer use curly braces for compound statements and class or function bodies, but you will indent another step, similar to how YAML works. How big this indentation is, you decide. I use 4 spaces, but you may use tabs, or other amounts, you can even mix indentation styles. Of course it is best to choose just one style and stick with it.

    #!python
    def toBeOrNotToBe(a):
        if a:
            print(a, "is")
            print(not a, "is not")
    #!php
    function toBeOrNotToBe($a) {
        if($a) {
            echo $a, " is\n";
            echo !$a, " is not\n";
        }
    }

Notice you don't need parentheses around the if's expression, and the blocks are never closed (unless a new line with lower indent is encountered). Also notice you don't need a statement terminator besides a newline, like you need the semicolon in PHP.

Be aware that print is a special case statement in Python 22, not a regular function call. This is similar to php's echo.

If you need an empty block, you'd use the $pass$ statement:

#!python
def thisDoesNothing():
    pass
def thisNeither():
    if False:
        pass

You may keep a block at one line, as long as it poses no ambiguity to the parser. Therefore

#!python
def thisDoesNothing(): pass

Is the same as the above version, but

#!python
def thisNeither(): if False: pass

renders a syntax error. The following version, however, is ok:

#!python
def thisNeither():
    if False: pass

Control structures

Flow control

If-statements work as follows:

    #!python
    if a:
        print(a)
    elif b:
        print(b)
    else:
        print("?")
    #!php
    if($a) {
        echo $a;
    } elseif($b) {
        echo $b;
    } else {
        echo "?";
    }

Note that the following piece of code would render a syntax error in python.

    #!python
    if a: pass
    else if b: pass
    #!php
    if($a) ;
    else if($b) ;

Switch statements don't exist.

Loops

The C-style for-loops don't exist in Python. You should use sequences to iterate over. Sequence types are more thoroughly explained in the documentation, but for now it suffices to say that a sequence is best compared to a (non-associative) array in PHP.

Python-style for-loops are best compared to PHP's foreach. Following code, using a range of numeric values as a sequence iterated over, is equivalent:

    #!python
    for i in range(0, 10):
        pass
    #!php
    foreach(range(0, 10) as $i)
        ;
    // or
    for($i = 0; $i < 10; $i ++)
        ;

Both would translate into the following C-style for-loop:

    #!C
    int i;
    for(i = 0; i < 10; i ++)
        ;

While loops are present in Python, with effectively the same syntax as in PHP:

    #!python
    i = 0
    while i < 10:
        print i
        i += 1

but do-while loops aren't.

Comments

Comments start with a hash (#) and end with a newline (just like PHP's # and // comments). Comments spanning multiple lines don't exist.

Built-in types

First of all, you can check types of variables by using type(). Try using the interpreter to find out how types are handled.

I won't cover all types, but basically the most common 6 built-in types are:

Variables

Variables have no special prefix as in PHP. All variables are of the same order, which means that a function is a variable too, so is a class, so is True, so is NoneType which is the type() of None.

Operators

Operators work pretty much the same as in PHP. Some differences are:

Operation Python PHP
String concatenation a + b $a . $b
Boolean expressions not a or b and c !$a || $b && $c
Member access obj.property $obj->property

Python has a few added nice features with operators, e.g. slicing in sequence types using the brackets operators:

Python PHP
a = [1, 2, 3] $a = array(1, 2, 3)
b = a[1:2] $b = array_slice($a, 1, 1)

(Note that Python uses indexes rather than lengths for the second argument)

... and in Python 2, the string formatting operator:

Python2 Python3 PHP
a = "string %d formatted" % 1 a = "string {0:d} formatted".format(1) $a = sprintf("string %d formatted", 1)

Functions

Functions are defined using the def keyword. A function consists of a name, an argument list and a body. The simplest function definition is as follows:

#!python
def f(): pass

The argument list may contain positional arguments with or without default values (which are grammatically equivalent to PHP arguments), keyword arguments with or without default values (which means that you can juggle the argument order around when calling the function) and a list of arbritrary arguments or keyword arguments, absorbed by a tuple or a dict at call time.

#!python
def fn1(a, b): # regular, positional arguments, and required by default
    print (a + " and " + b)

def fn2(c="c"):
    print (c)

def fn3(*args, **kwargs):
    print (args)
    print (kwargs)

fn1("a", "b")       # "a and b"
fn1(b="b", a="a")   # "a and b"
fn2()               # "c"
fn2("d")            # "d"
fn3()               # () {} (an empty list and an empty dict)
fn3(1, 2, 3,
    a="foo", b="bar") # (1, 2, 3) {'a': 'foo', 'b': 'bar'}

Functions may return and yield values. Yielding values makes the function a generator, which is a compile-time feature of python, basically meaning you can iterate over multiple variables returned by a function, breaking the current execution of the function itself. Again, examples tell more. The range function could be implemented as follows:

#!python
def range(start, end):
    i = start
    while ( i < end ):
        yield i
        i += 1

for i in range(5, 8):
    print(i)

Resulting in:

5
6
7

Classes

There is also a funny similarity between Python and PHP classes. In python, special methods have the form __method__, where "method" is the special name in case. In PHP, we know the same thing for e.g. __toString(), __call(), etc.

The following is an example of classes in Python.

#!python
class Point:
    def __init__(self, x, y):
        self._x = x
        self._y = y

class Circle(Point): # let the class Circle inherit from the class Point
    def __init__(self, x, y, radius):
        super(Circle, self).__init__(x, y) # Explicitly call the parent constructor
        self._radius = radius

    def __str__(self):
        return "This is a circle"

def another_str_impl(obj):
    return "It is a " + str(type(obj)) + " instance";

c = Circle(10, 10, 10)
print(c) # "This is a circle"

Circle.__str__ = another_str_impl;

print(c) # It is a <class '__main__.Circle'> instance

As you can see, the 'init' is the constructor, __str__ is more or less the same as PHP's __toString(). Also note the omission of a new keyword; Pythons classes are called directly.

The following table shows a mapping of PHP's magic methods to Python's

PHP Python
__get __getattr__
__set __setattr__
__isset not available
__unset __delattr__
__call not available
__construct __init__
__destruct __del__
__invoke __call__
ArrayAccess::offsetGet __getitem__
ArrayAccess::offsetSet __setitem__
ArrayAccess::offsetExists not available
ArrayAccess::offsetUnset __delitem__

Also, implementing Iterators like in PHP is even easier in Python. Simply implement the __iter__ method generating all items, and you're good to go:

#!python
class A:
    def __init__(self):
        self._items = ["a", "b", "c"]

    def __iter__(self):
        self._items.reverse();
        for i in self._items:
            yield i
a = A()
for i in a:
    print(i)

for i in a:
    print(i)

Result:

c
b
a
a
b
c

Ultimately, you can recreate virtually all types with the magic methods in Python. See the entire list in the documentation.

Modules

A module in Python is a file containing code. The name of the module is the filename, and the code can be used in other files by importing the modules. The file run from the command line is called the "main" module, which makes the name of the special __name__ variable contain "__main__".

file1.py:

#!python
import file2
from file3 import bar #import bar from file3 as a local name 'bar'

print(__name__)
print(file2.foo)
print(bar)

file2.py:

#!python    
foo="foo"

file3.py:

#!python
bar = "bar"

Running file1.py from the command line would give the following results:

#!shell
$ python file1.py 
__main__
foo
bar

The most common practice is to put classes into modules which are then imported in other modules. It is considered bad practice to have files run code that is not needed for their bootstrapping, so main code is usually fenced inside an if, checking main is the current scope:

file1.py:

#!python
import file2
if __name__ == "__main__":
    print("file1.py says hi")

file2.py:

#!python
if __name__ == "__main__":
    print("file2.py says hi")

Running these file from the command line:

#!shell
$ python file1.py
file1.py says hi
$ python file2.py
file2.py says hi

Decorators

Decorators are functions or classes that can change a piece of code run-time, but does not clutter the code. This makes for excellent aspect-oriented programming, being able to mix in any kind of functionality into your class or function. I'll just leave it with a simple example:

#!python
debugging = False

def traced(fn):
    def decorated(*args, **kwargs):
        if debugging:
            print("Enter: " + fn.__name__ + "()");
        fn(*args, **kwargs)
        if debugging:
            print("Exit: " + fn.__name__ + "()");
    return decorated

@traced
def foo(bar, baz):
    print("bar: ", bar, "\nbaz: ", baz)
    foo2(bar, baz)

@traced
def foo2(bar, baz):
    pass

foo("hello", "world");
debugging = True
foo("world", "hello!");

The output would be:

#!shell
$ python ./test2.py
bar:  hello 
baz:  world
Enter: foo()
bar:  world 
baz:  hello!
Enter: foo2()
Exit: foo2()
Exit: foo()

Docstring

Python has a language feature which let you document classes and functions by inserting a string between the declaration and it's definition. This documentation is available at runtime in the __doc__ property.

#!python
def fn():
    "This function actually does nothing"
    pass

print fn.__doc__ # prints the docstring

This makes it very easy to get documentation on code using the interpreter:

#!shell
>>> import os
>>> print os.path.realpath.__doc__
Return the canonical path of the specified filename, eliminating any
symbolic links encountered in the path.

... and much, much, much, much, much more.....

This post could continue for ages. But I'm going to stop here. I hope I have given you an appetite. Python is one of the most flexible languages out there, and I'd really encourage you to try something with the Django web Framework, Google App Engine, or get started building GTK or QT desktop applications, binding to VLC's library, or write your own threaded web server, the possibilities are endless.

If you're getting enthusiastic, just go monk and simply read the Python documentation.

Have fun :)


  1. Python 2 is rapidly becoming outdated, but let me tell you that learning python 2 won't be wasted time. Code samples in this post work in both python 2 and 3. ↩︎

  2. In Python 3 this actually became a regular function, so all print calls in the examples have parentheses, even though they're not needed in Python 2. ↩︎


< Return to main page


You're looking at a very minimalistic archived version of this website. I wish to preserve to content, but I no longer wish to maintain Wordpress, nor handle the abuse that comes with that.