# HG changeset patch # User Shantanu # Date 1276176244 -19800 # Node ID 597ee2fcb795a12518b64c78133c246b55abb76d # Parent bb52cf47e920c60d8edf47d26812a1ad841f02bd# Parent 449760bc40896179b0f44ae24c9b36e738e78b36 Merged the branches. diff -r bb52cf47e920 -r 597ee2fcb795 basic_python/oop.rst --- a/basic_python/oop.rst Thu Jun 10 18:53:49 2010 +0530 +++ b/basic_python/oop.rst Thu Jun 10 18:54:04 2010 +0530 @@ -3,7 +3,7 @@ In the previous sections we learnt about functions which provide certain level of abstraction to our code by holding the code which performs one or more -specific functionalities. We were able to use this function as many times as we +specific functionality. We were able to use this function as many times as we wanted. In addition to functions, Python also higher level of abstractions through *Classes* and *Objects*. *Objects* can be loosely defined as a collection of a set of data items and a set of methods. The data items can be @@ -31,7 +31,7 @@ which it was called as the first argument. It is conventionally given the name, *self*. Note that *self* is only a convention. You can use any other name, but the first argument to the method will always be the same object of the class -from which the method was called. The data memebers that belong to the class are +from which the method was called. The data members that belong to the class are called as *class attributes*. *Class attributes* are preceded by the object of the class and a dot. In the above example, *name* is a class attribute since it is preceded by the *self* object. *Class attributes* can be accessed from @@ -70,3 +70,45 @@ print e.name AttributeError: Employee instance has no attribute 'name' +It is also possible to assign values to the attributes using the above notation:: + + >>> emp = Employee() + >>> emp.name = 'John' + >>> print emp.name + John + +Magic methods +------------- + +Python reserves a number of names starting and ending with **__**. Note that it +is a double underscore. We must not invent names of this kind in our programs. +These methods are generally referred to as *Magic methods* or sometimes called +as *Special Methods*. Each *Magic method* performs a specific function. One such +magic method we will discuss now is **__init__** method. If you are from C++ +background, the **__init__** method is analogous to the class constructor. This +method is called a constructor because, it is implicitly called everytime a new +instance of the class is created. So effectively **__init__** method constructs +the object from the class and sets up some initial values for the object. Other +than the above special properties, the **__init__** method is similar to any other +class method. The argument passing rules are same for **__init__** method. Although, +since **__init__** is called when the object is created we need to pass the +arguments to the class name we call while creating the object. It passes the +arguments to the **__init__** method:: + + class Employee: + def __init__(self, name): + self.name = name + + def getName(self): + return self.name + + >>> emp = Employee('John') + >>> print emp.getName() + John + + +Writing Object Oriented Code +---------------------------- + +Object oriented code mainly encompasses three components: Encapsulation, Inheritence and Polymorphism. +Lets briefly look at each of them with examples. diff -r bb52cf47e920 -r 597ee2fcb795 tdd/tdd.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tdd/tdd.rst Thu Jun 10 18:54:04 2010 +0530 @@ -0,0 +1,78 @@ +Fundamentals +============ + +Test Driven Development, abbreviated as TDD is a method of software +development which banks on the idea of writing test cases that fail for the +code that doesn't even exist yet. The actual code is written later to pass +the test and then refactored. + +Writing tests +============= + +Writing a test is simple. Writing a failing test? It is much more simple. +Let us consider a very simple program which returns the Greatest Common +Divisor (GCD) of two numbers. Since the test cases for the code is written +prior to the code itself, it is necessary to have a clear idea of the code +units that our program will contain. Let us attempt to clearly define the +code units in our case of a GCD program. Let our program contain one and +only one function called gcd() which takes in two arguments as parameters. +These arguments are the numbers for which GCD must be computed. The gcd() +function returns a single value which is the GCD of the two arguments +passed. So if we want to find out GCD of 44, 23, I will call my code unit +as c = gcd(44, 23) where c will contain the GCD of those two numbers. + +Now we have defined our code units, how will we write tests? Before writing +the test, a very fundamental question arises in our minds. How do tests +look like? So let us answer this question first. Tests are nothing but a +series of assertions which are either True or False depending on the +expected behaviour of the code. We tell our tests whether our code unit +asserts True or asserts False based on the expected behaviour of the code +units. If we happen to run the tests now we are sure to get errors. Oh! But +why? We don't even have the function gcd to call. The test code doesn't +even compile! So what should we do now? So the idea is to first write the +stubs for the code units before we start writing tests. This is necessary +for two reasons. Firstly, by writing the stubs for the code units we will +be able to correctly decide and fix on to the code units that we have +planned to include in our program. We have a clear cut idea as to how our +program is structured, how the tests must be written among other +things. Secondly, the tests must at least compile and then fail! If the +tests don't even compile, that doesn't mean the tests failed. It means +it was a failure on the programmer's part. Let us define our stub:: + + def gcd(a, b): + pass + +This stub does nothing other than defining a new function called gcd which +takes two parameters a and b for which the GCD must be calculated. The body +of the function just contains pass which means it does nothing, i.e. empty. +We have our stub ready. One important thing we need to keep in mind when +we adopt TDD methodology is that we need to have a clear set of results +defined for our code units. To put it more clearly, for every given set of +inputs as test case we must have, before hand, the exact outputs that are +expected for those input test cases. If we don't have that we have failed +in the first step of the TDD methodology itself. We must never run for +outputs for our test cases after we have the code ready or even while +writing tests. The expected outputs/behaviour must be in our hands before +we start writing tests. Therefore let us define our test cases and the +expected output for those inputs. Let one of our test cases be 48 and 64 +as *a* and *b* respectively. For this test case we know that the GCD is +16. So that is the expected output. Let our second test case be 44 and +19 as *a* and *b* respectively. We know that their GCD is 1 by simple paper +and pen calculation. + +Now we know what a test is? What are the ingredients required to write +tests? So what else should we wait for? Let us write our first test!:: + + tc1 = gcd(48, 64) + if tc1 != 16: + print "Test failed for the case a=48 and b=64. Expected 16. Obtained + %d instead." % tc1 + exit(1) + + tc2 = gcd(44, 19) + if tc2 != 1: + print "Test failed for the case a=44 and b=19. Expected 1. Obtained + %d instead." % tc2 + exit(1) + + print "All tests passed!"