[Tutor] Constructs

Steven D'Aprano steve at pearwood.info
Tue Apr 8 16:39:59 CEST 2014

On Tue, Apr 08, 2014 at 11:10:57AM +0530, Santosh Kumar wrote:
>   1 #!/usr/bin/python
>   2
>   3 class shape:
>   4   def __init__(self,x,y):
>   5     self.x = x
>   6     self.y = y
>   7   description = "This shape has not been described yet"
>   8   author = "Nobody has claimed to make this shape yet"

Notice that the body of the __init__ method is indented (by two spaces 
-- four is recommended) from the method header. The body ends once the 
indentation returns to the previous level. So this piece of code has 
three levels of indentation:

    Level 0: "class shape" is not indented;

    Level 1: "def __init__" is 1 indent in;

    Level 2: the body of the method is 2 indents in;

    Level 1: the "description" and "author" lines are outdented 
             from 2 back to 1.

Because "description" and "author" are indented level with the __init__ 
definition (NOT the body of the method, the def header) that makes them 
*class attributes*. They are bound to the class itself, not the 
instance, and are shared by all instances. In Java terms they would be 
called "static variables".

>   9
>  10   def __init__(self,x,y,z):
>  11     self.x = x
>  12     self.y = y
>  13     self.z = z

This now overwrites the existing __init__ method with a new method, also 
called __init__, that takes three arguments instead of two. Because 
methods are values exactly the same as strings, floats, bools and so 
forth, you can only have one method with the same name. If you wrote:

x = 1
x = 2

of course you would expect that the second assignment to x overwrites 
the first assignment -- x cannot have two different values at the same 
time. The same applies to methods: you cannot have __init__ set to a 
method taking arguments x, y, z and a method taking arguments x, y at 
the same time. The newest assignment wins.

Java methods are fixed at compile-time, so it is easy for the compiler 
to decide which constructor method to call at compile-time: if there are 
two arguments, call the first method, if there are three, call the 
second. But Python methods are values, and can be replaced on the fly at 
run-time. Python can do run-time polymorphism, but not in the same way 
that you do it with Java. Instead, you should define the method with 
default arguments:

    def __init__(self, x, y, z=None):
        self.x = x
        self.y = y
        if z is not None:
            self.z = z

>  14   print "The values are %d,%d,%d" %(self.x,self.y,self.z)

This line is outdented relative to the body of the __init__ 
method, so it too is at the class scope. That means that the print 
statement will be executed at class definition time. The problem is, at 
class definition time, there is no instance yet, even the class doesn't 
exist yet, so the reference to "self" will fail with NameError.

I think what you want is for the print to be indented one more level, 
so it is inside the method:

    def __init__(self,x,y,z):
        self.x = x
        self.y = y
        self.z = z
        print "The values are %d,%d,%d" % (self.x, self.y, self.z)


More information about the Tutor mailing list