| Author: | Jeroen Ruigrok van der Werven <asmodai@in-nomine.org> |
|---|---|
| Version: | $Id$ |
A quick overview of Python from an object-oriented programming language point of view.
This article will also detail the relevant concepts.
Python version 2.5 or later is assumed.
In the field of programming languages there are a number of ways in which to address the fundamental logic of how a programming language works. This is commonly called a programming paradigm. The most simplistic example is the procedural programming example. In this example every problem gets solved by writing so-called procedures that handle parts of the bigger solution.
Another programming paradigm is that of object-oriented programming. In this programming paradigm the core concept is that of objects. The objects are the basic layer of abstraction and each object has a specific role.
I am indebted to the following people for explanations, guidance, and proofreading:
The class is the highest (TODO: lowest?) abstract level possible, it defines the conceptual entity we are trying to abstract along with all its characteristics. A class by itself is best viewed as a sort of blueprint, in order to use it we need to build something from the blueprint so that we may use it.
A very basic class definition is the following:
class Transformer(object):
pass
An object is a specific instantiation of a class. Two different instantiations of the same class may very well be duplicates of each other, but they are nonetheless completely distinct entities. Messing around with one will not influence the other.
A simple example of instatiating two subclasses of the Transformer class:
class Autobot(Transformer):
pass
class Decepticon(Transformer):
pass
TODO:
A method defines an action associated with a class or an object. In other programming languages this would be called a function or subroutine. The main purpose of a method is the reading and writing of data associated with the class or object. Every method has a required first parameter called self. This parameter is a reference to the object it is associated with in order to work with the correct object and its data.
An example of a method definition at class level:
class Transformer(object):
def identify(self):
print "I am a Transformer."
This way the method is unusable thought. In order to be able to use the method we first need to instantiate an object from this class. If we try to approach the method directly through the class we will be told that the method is unbound.
Error
TypeError: unbound method identify() must be called with Transformer instance as first argument (got nothing instead)
So now to instantiate a Transformer object and call the associated method:
>>> class Transformer(object): ... def identify(self): ... print "I am a Transformer." >>> t = Transformer() >>> t.identify() I am a Transformer.
TODO:
TODO:
TODO:
TODO:
Python has limited support for protection of various language parts as compared to other languages.
When importing from a module Python will ignore any objects or variables that are prefixed with an underscore (_).
TODO:
A generator is a mix of a function and an iterator.
A common programming pattern is an iterator (in pseudo-code):
i = 0
for i < 10:
print 'This is iteration', i
increment(i)
This will initialize the variable i to 0, the iteration loop is entered and will not be left until the condition i < 10 has been satisfied. Every iteration will start from the part right after the condition and works its way down the code in the loop, unless interrupted. So in this case the loop will print This is iteration followed by the current value of i. Next the value of i is incremented and we wrap-around to the beginning of the iteration loop. When the condition finally gets satisfied the entire loop is skipped and the execution of the program continues with the code right after the loop.
The only problem with an iterator is that you are required to let it run its course while it does whatever it is supposed to do and let it store its results in some variable. This means that you either lose control of the execution for a while, you need to store a lot of results, or possibly even both. In some cases it would make more sense to have a single iterative result but only whenever you call it. And every next call will give you the next result. This is what a generator is. As the name implies it generates a result on every invocation and then returns (or yields) the result to the main program.
TODO:
A list comprehension is a way to create a list programmatically.
Most simplistic form:
[expression for item in a_list]
More advanced form:
>>> a_list = ((True, 1), (False, 2), (True, 3)) >>> new_list = [item for item in a_list if item[0]] >>> new_list [(True, 1), (True, 3)]
TODO:
According to the textbook definition a closure is 'a function that is evaluated in an environment containing one or more bound variables'.
The function or method can be either a normal or an anonymous one if the programming language provides for it.
When the function is evaluated it has access to the variables that were available in its lexical scope at the time of the definition of the function. Closures are commonly used as an argument to another function or as a return value.
Closures are used for their data or information hiding aspect.
Closures allow for stateful functions where the state is hidden inside the function that produced the function object.
In the following example _inc() is a closure. Normally you would have to use something like a Counter class or a generator for this to work or pass the state explicitly.
>>> def counter(start=0, step=1): ... x = [start] ... def _inc(): ... x[0] += step ... return x[0] ... return _inc >>> c = counter() >>> c() 1 >>> c() 2
TODO:
Metaprogramming can be very powerful, but unfortunately it also can introduce the so-called 'monkey patching'. A monkey patch or monkey patching is the practise of adjusting the runtime behaviour of a program without modifying the source code of the program. Given the fact the source code's intentions and the actual observed result from the program differ it is not advised to use monkey patching.
TODO:
Object-oriented programming uses error reporting in a different way. Instead of raising an error it raises or throws an exception.
For a new python module start with a directory named after the package. Put all your python files underneath separated by functionality and when a particular part becomes too big or spawning too many files make another subdirectory. This allows you to keep the namespace tidy without resorting to Java-style namespaces.