Python/Java OOish type question

Kirby Urner urner at alumni.princeton.edu
Thu Aug 31 03:35:08 EDT 2000


Trying to get clear on something.

I want to have a class with lots of operations defined, 
and thousands of objects which don't carry the overhead 
of those operations in memory (because they've already 
been defined and should be the same for every instance).

In Java, you can do these abstract classes full of static 
ops, and subclass these for the purpose of making objects.  
But these objects will inevitably have some instantiated 
variables that feed into the ops -- and yet static methods 
can't contain instantiated variables.  So I end up with 
something like:

 abstract class quatops {
         
     protected quat add(quat a, quat b){
        return new quat(a.value + b.value);
     }
 }

 class quat extends quatops {
    
    int value = 0;
    
    public quat(int value){
        this.value = value;
    }

    public quat add(quat b){
        return super.add(this,b);
    }
 }

 public class play1 {
    public static void main(String[] args){
        quat a = new quat(1);
        quat b = new quat(2);
        quat c = a.add(b);
        System.out.println(c.value);
    }
 }

When the above executes (which it does), I get 3 (the expected
answer).

However, I think it's a pity to carry the overhead of an 'add'
method in each quat (above example), merely for the purpose of
invoking a static superclass version of this operation -- even 
if the unreplicated static version is in principle much longer 
than these subclass invocations (which might be one-liners).

Of course there's another way to go, which is like what Java 
does with the abstract Math class -- you don't subclass Math,
but take advantage of its static methods as external to your
objects (passed as parameters).  

But I'm philosophically invested in a design which stuffs ops 
inside the objects in question, which is why the above (why
this line of questioning).

My impression is Python gets around this by saving the method
once, statically, even though the method is on the receiving 
end of instantiated variables, i.e. when I write:

  class quat:

     def __init__(self,value):
         self.value = value
          
     def add(self,b):
         return quat(self.value + b.value)

and then go:
 
  >>> q1 = quat(1)
  >>> q2 = quat(2)
  >>> q3 = q1.add(q2)
  >>> q3.value
  3

I'm NOT getting copies of the 'add' method inside every quat 
object.  Or am I?  Isn't it the case that quat is basically
instantiating once, leaving room for 'self' to go through as
a kind of parameter, different for each object of type quat
(including subtypes)?

Methods are like class variables in this sense (more dictionary
entries).  So whereas Java abstract classes have no room for
any instantiated object data (are "flat"), Python classes are
just deep enough to give every instantiated object an anchor
back to the same method bytecodes.

I think this because of what I see in the __dict__ of each
of the above:

 >>> q1.__dict__
 {'value': 1}
 >>> q2.__dict__
 {'value': 2}
 >>> quat.__dict__
 {'__init__': <function __init__ at 12afb00>, '__doc__': None, 
 'add': <function   add at 12afe10>, '__module__': '__main__'}

Only the class dictionary contains the function.

You can get memory references for q1.add and q2.add, but the
different returns correspond to the locations of q1 and q2 
as objects -- doesn't tell me whether the add method is 
actually taking up bytes inside q1 and q2.

 >>> q1.add
 <method quat.add of quat instance at 1ae9b00>
 >>> q2.add
 <method quat.add of quat instance at 1aeb3d0>
 >>> q2
 <__main__.quat instance at 1aeb3d0>

I may be rather confused here.  Anyone with the patience to 
help me sort it out?

Kirby
  



More information about the Python-list mailing list