1

I am getting an error when I call a subclass from another class, but not when I call it directly. It seems that when I create an instance of this subclass from a different class the information in the superclass is not getting passed to the subclass.

class HBatom(object):
    def __init__(self, struct, sele, **kwargs):
        self.struct = struct
        self.sele = sele

class HDonor(HBatom):
    def __init__(self,struct,sele,**kwargs):
        super(HDonor,self).__init__(struct,sele,**kwargs)
        self.find_H()
    def find_H(self):
        bonded = self.struct.select(''.join(["bonded to ", self.sele.getSelstr()]))

This works

import HBonds
HB = HBonds.HDonor(structure,Nsel,f_wat=1)

But when I create an instance of a class that contains a dictionary of HDonors and then tell it to populate I get an error

HN = HBonds.HNtwrk(structure,1)
HN.build_HNtwrk()

AttributeError: 'HDonor' object has no attribute 'sele'

Executing with pdb shows me that in the second case self contains no attributes of the HBatom parent class. How is it possible for self to contain that info in the first case but not in the second?

Sorry, I didn't include HNtwrk in the original post. The total code is almost 400 lines, so I don't want to include more than necessary. Here are the relevant parts of HNtwrk

class HNtwrk:
  def __init__(self,structure, f_wat = 0):
    self.f_wat = f_wat
    self.struct = structure
    self.rh_o = 2.5
    self.rn_o = 3.5
    self.Dons = dict()
    self.Accs = dict()

def build_HNtwrk(self):
    Dsele = self.struct.select(DonStr)
    Asele = self.struct.select(AccStr)
    self.addDons(Dsele)
    self.addAccs(Asele)

def addDons(self, Dsele):
    for pairs in iterNeighbors(Dsele,self.rn_o,Asele):
        iN = pairs[0].getIndices()[0]
        iA = pairs[1].getIndices()[0]

        if iN not in self.Dons:
            Hdon = HDonor(self.struct,pairs[0].getSelstr,f_wat=self.f_wat)
            self.Dons[iN] = Hdon

The code trips when I set Hdon because HDonor.find_H() requires HBatom attributes. It is as if HBatom.__init__() is not called during the HDonor init when an HDonor instance is created from HNtwrk. Just to be clear, HNtwrk appears in the same file as the other classes.

johnjax
  • 133
  • 1
  • 6

3 Answers3

0

Use the concrete superclass name, that is HBatom, instead of super.

When you call super(HDonor, self), and self is actually a child of HDonor, super's result will pass function calls to HDonor class, not the HBatom as you expected.

See this answer for more details on why super creates problems.

Community
  • 1
  • 1
Rafał Rawicki
  • 22,324
  • 5
  • 59
  • 79
  • You make a good point about using super, however changing to HBatom.__init__(self,struct,sele,**kwargs) had no effect in this case – johnjax Apr 30 '12 at 15:39
0

You haven't shown the code for HNtwrk or build_HNtwrk, but I'll guess that HNtwrk.__init__ doesn't invoke the parent's __init__ method.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • It sounds like HNtwrk doesn't inherit HBatom, but rather initializes an `HBonds` object. I agree it should be shown though. – David Robinson Apr 28 '12 at 03:53
  • I've now included the relevant (I hope) parts of HNtwrk. HNtwrk does not invoke the HBatom \__init__ because it is not meant to be a subclass of HBatom. Instead it is meant to contain dictionaries of HBatoms and track the relationships between them. – johnjax Apr 30 '12 at 15:40
0

Problem solved. Turns out it wasn't an inheritance issue at all. I was getting the problem because I called

Hdon = HDonor(self.struct,pairs[0].getSelstr,f_wat=self.f_wat)

instead of which should have been called with

Hdon = HDonor(self.struct,pairs[0].getSelstr(),f_wat=self.f_wat)

Thus I wasn't passing what I thought I was passing and this triggered a poorly written exception that I had included in HBatom.__init__() (which I failed to include as a code snippet). Thanks to those who offered suggestions. In the future I will create a separate small code that will isolate the problem and post the full code.

johnjax
  • 133
  • 1
  • 6