[Tutor] Perl and Python OOP comparisons

Danny Yoo dyoo@hkn.eecs.berkeley.edu
Tue Nov 26 04:52:02 2002


On Mon, 25 Nov 2002, Magnus Lycka wrote:

> > > This is probably a pretty basic question, so I apologize for any
> > > eye-rolling it may cause - I'm a perl guy trying to use python, and
> > > it's tough to get my brain going in a different direction.  :-)

Hi Wade,

Welcome!  Python's not so different from Perl; there are a few design
differences, but I think you'll enjoy the ride.  *grin*



> > > And the function is defined as:
> > >
> > >   def PlayAudio(self,event):
>
> Ok, then I assume that it's not a function in the scope of the module,
> but a method inside the same class as the EVT_... I guess you bind the
> event in __init__. Right? Otherwise the parameter "self" seems a bit
> odd.
>
> Have you used object-oriented Perl?


If you've done some OOP in Perl, you may have seen code like this:

###
## Perl code --- avert your eyes!  *grin*
package Person;

sub new {
    my $class = shift;
    my $self = bless {}, $class;
    $self->init(@_);
    return $self;
}

sub init {
    my ($self, $name, $height) = @_;
    $self->{name} = $name;
    $self->{height} = $height;
}

sub sayGreeting {
    my $self = shift;
    print "Hello!  My name is $self->{name}. ";
    print "I am $self->{height} feet tall!\n";
}

package main;



my $sharky = Person->new("Saruman", 9);
$sharky->sayGreeting();
###


In Perl, there's a lot of 'freedom' up front: we get to choose what kind
of object you want to bless, and in the example above, we used a hash
reference.  This "$self" acts as a container to store the state of the
object.


In Python, most of the machinery used to actually construct this 'self'
state thing comes built-in with the language:

###
class Person:
    def __init__(self, name, height):
        self.name = name
        self.height = height

    def sayGreeting(self):
        print "Hello!  My name is", self.name,
        print "I am", self.height, "feet tall!"
###


But the role of this 'self' in Python mirrors that in Perl --- it stores
state.  When we do things like:


###
###  Python interactive interpreter session:
###
>>> frodo = Person("Frodo Baggins", 4)
>>> frodo.sayGreeting()
Hello!  My name is Frodo Baggins I am 4 feet tall!
###

the reason that 'frodo' can say "Frodo Baggins" is because he's keeping
track of his name in his "self".  His identity is his own.


If we start making more people:

###
>>> took = Person("Peregrin Took", 5)
>>> took.sayGreeting()
Hello!  My name is Peregrin Took I am 5 feet tall!
###

we see that what distinguishes 'frodo' from 'took' is how 'self' is being
initialized.



We can think that, behind the scenes, something like this is happening:

      frodo.sayGreeting()

             |
             | transforms into
             v

    Person.sayGreeting(frodo)


When we do a method call, 'self' will refer to the instance that does the
action.  In this sense, we can think of method calls on an instance as
simply subroutines with slightly special syntax.




Let's go back to what you were talking about before:

> > >   def PlayAudio(self,event):
>
> Ok, then I assume that it's not a function in the scope of the module,
> but a method inside the same class as the EVT_...

Yes, PlayAudio would be considered a "method" of its class.  Python's
classes will force the issue by making us physically nest these methods
within the 'class' block, so that, if our class definition is short, we
can see right off the bat which class is being defined.


In Perl, you have to scan upward till you hit the most recent 'package'
declaration, and then scan downward till you see a 'package main' to see
where the class definition ends.  In Python, the boundaries of a class are
definted in a similar way, but by using indentation, not 'package'
statements.



Anything that's not in the block of a 'class:' can be considered outside
of the class... that is, as long as we don't start poking and meddling
into our class.  But just to see what kind of evil things we can do...

###
###
>>> Person.getHeight = lambda self: self.height   # aagh!?!  My eyes!
>>> frodo.getHeight
<bound method Person.<lambda> of <__main__.Person instance at 0x81550f4>>
>>> frodo.getHeight()
4
###

The example above will crazy-glue a new method to the Person class.  So
there is potential of defining additional functionality of a class without
being in the class's block.  But it's often not a good idea to do this,
and most people do not expect to see such obfuscated code.  *grin*



> > > However, when I move that function to another .py module (I'm trying
> > > to group like functions together in modules), import the module, and
> > > call it like:
>
> A Python class must be defined in one file. (As in Perl, right?)

Sadly, no: its very possible to spread a class definition in Perl to
several different files.  It's all too easy to revisit the class with a
single misplaced 'package' statement in Perl.

It's also possible to munge up a previous class's definition in Python, as
we've seen above, but it's not something that should be discussed in the
dark.  *grin*



I hope some of this made sense.  *grin*  Good luck to you!