title: Python class inheritance/Logic gate & circuit example
body: <p>I'm currently self-learning Python, and I'm reading 'Problem Solving with Algorithms and Data Structures' (Brad Miller, David Ranum). I've stumbled upon the basic example of inheritance. Although I can see what it does, I need an explanation, <em>how</em> it works actually. The Code is as follows:</p>
  
  <pre><code>class LogicGate:
  
      def __init__(self,n):
          self.name = n
          self.output = None
  
      def getName(self):
          return self.name
  
      def getOutput(self):
          self.output = self.performGateLogic()
          return self.output
  
  
  class BinaryGate(LogicGate):
  
      def __init__(self,n):
          LogicGate.__init__(self,n)
  
          self.pinA = None
          self.pinB = None
  
      def getPinA(self):
          if self.pinA == None:
              return int(input("Enter Pin A input for gate "+self.getName()+"--&gt;"))
          else:
              return self.pinA.getFrom().getOutput()
  
      def getPinB(self):
          if self.pinB == None:
              return int(input("Enter Pin B input for gate "+self.getName()+"--&gt;"))
          else:
              return self.pinB.getFrom().getOutput()
  
      def setNextPin(self,source):
          if self.pinA == None:
              self.pinA = source
          else:
              if self.pinB == None:
                  self.pinB = source
              else:
                  print("Cannot Connect: NO EMPTY PINS on this gate")
  
  
  class AndGate(BinaryGate):
  
      def __init__(self,n):
          BinaryGate.__init__(self,n)
  
      def performGateLogic(self):
  
          a = self.getPinA()
          b = self.getPinB()
          if a==1 and b==1:
              return 1
          else:
              return 0
  
  class OrGate(BinaryGate):
  
      def __init__(self,n):
          BinaryGate.__init__(self,n)
  
      def performGateLogic(self):
  
          a = self.getPinA()
          b = self.getPinB()
          if a ==1 or b==1:
              return 1
          else:
              return 0
  
  class UnaryGate(LogicGate):
  
      def __init__(self,n):
          LogicGate.__init__(self,n)
  
          self.pin = None
  
      def getPin(self):
          if self.pin == None:
              return int(input("Enter Pin input for gate "+self.getName()+"--&gt;"))
          else:
              return self.pin.getFrom().getOutput()
  
      def setNextPin(self,source):
          if self.pin == None:
              self.pin = source
          else:
              print("Cannot Connect: NO EMPTY PINS on this gate")
  
  
  class NotGate(UnaryGate):
  
      def __init__(self,n):
          UnaryGate.__init__(self,n)
  
      def performGateLogic(self):
          if self.getPin():
              return 0
          else:
              return 1
  
  
  class Connector:
  
      def __init__(self, fgate, tgate):
          self.fromgate = fgate
          self.togate = tgate
  
          tgate.setNextPin(self)
  
      def getFrom(self):
          return self.fromgate
  
      def getTo(self):
          return self.togate
  
  
  def main():
     g1 = AndGate("G1")
     g2 = AndGate("G2")
     g3 = OrGate("G3")
     g4 = NotGate("G4")
     c1 = Connector(g1,g3)
     c2 = Connector(g2,g3)
     c3 = Connector(g3,g4)
     print(g4.getOutput())
  
  main()
  </code></pre>
  
  <p>I'm mostly doubted by the <code>tgate.setNextPin(self)</code> statement in <code>Connector</code> class <code>__init__</code>. Is it a method call? If it is, why is it called with just one parameter, when there are two actually required by the <code>setNexPin</code> function in <code>UnaryGate</code> and <code>BinaryGate</code> classes <code>(self, source)</code>? How does the <code>fromgate</code> variable ends up as the <code>source</code> arrgument? Does this statement 'initiliaze' anything actually, and what?</p>
  
  <p>Next thing which troubles me is, for example, when I <code>print(type(g4))</code> before declaring <code>g4.getOutput()</code>, I get <code>&lt;class '__main__.OrGate'&gt;</code>, but when the <code>g4.getOutput()</code> starts, and functions start calling each other, to the point of calling <code>getPin</code> function, if I put <code>print (self.pinA)</code> before <code>return self.pinA.getFrom().getOutput()</code>, I get the <code>&lt;__main__.Connector object at 0x2b387e2f74d0&gt;</code>, although <code>self.Pin</code> is a variable from <code>g4</code> <code>OrGate</code> instance. How can one variable from one class instance can become object of another class, which isn't inheriting it? Does this have something with a work of <code>setNextPin()</code> function?</p>
  
  <p>Can someone explain this to me as I am new to OOP and thorougly confused by this piece of code. Thank you.</p>