title: Python: Passing a class member function to another class's callback
body: <p>Can I pass class A into class B so that B can run a callback using A's member function?</p>
  <p>I am trying to write a Python leg class for a robot I am building. I am using  a Raspberry Pi as the main computer, and Martin O'Hanlon's KY040 rotary encoder library <a href="https://github.com/martinohanlon/KY040" rel="nofollow noreferrer">KY040</a> to detect each 1/4 rotation of the leg. To this end, I watch for the first of several clicks, sleep for a short time, stop the servo, and now a 1/4 rotation has been achieved. In standalone, unthreaded code this works fine, but creating a class has been a challenge.</p>
  <p><strong>Details:</strong></p>
  <p>A threaded sentinel loop watches a boolean (<code>quarterTurn</code>) to signal that a rotation must be carried out.</p>
  <pre><code>def run(self):
      print &quot;leg running&quot;
      while self._running:
          sleep(.0001)
          if self.quarterTurn:
              print &quot;quarterTurn is: &quot; + str(self.quarterTurn)
              self.qTurn(self.quarterCount)
  </code></pre>
  <p><code>qTurn</code> accesses a pwm controller to activate the motors, and reset quarterTurn to false.</p>
  <pre><code>def qTurn(self, quarters):
      count = 0
  
      while count &lt; quarters:
          sleep(.0001)
          self.setMotor(self.maxPulse)
  
          if self.ClickedOnce:
              count = count + 1
              sleep(.17)
              self.parkMotor()
              sleep(.04)
              self.clickedOnce = False
  
      self.quarterTurn = False
  </code></pre>
  <p>The trick is that O'Hanlon's class is already threaded. On one hand, it is convenient, on the other, it makes my class more complex. The KY040 makes use of a callback function to provide feedback, but using this within my class is the source of my trouble.</p>
  <p>I need the callback to modify a a boolean in my leg class, but this function is only called by the KY040 class, which tries to pass itself into the function.</p>
  <pre><code>def rotaryChange(self, pin):
      self.clickedOnce = True
  </code></pre>
  <p>Since the code is open source (thank you, O'Hanlon), I thought I could modify the constructor of the KY040 to let me pass my leg class into it, so that I could modify the correct data.</p>
  <p>O'Hanlon's Original Constructor:</p>
  <pre><code>def __init__(self, clockPin, dataPin, switchPin=None, rotaryCallback=None, switchCallback=None,rotaryBouncetime=250, switchBouncetime=300):
      # persist values
      self.clockPin = clockPin
      self.dataPin = dataPin
      self.switchPin = switchPin
      self.rotaryCallback = rotaryCallback
      self.switchCallback = switchCallback
      self.rotaryBouncetime = rotaryBouncetime
      self.switchBouncetime = switchBouncetime
  
      #setup pins
      GPIO.setup(clockPin, GPIO.IN)
      GPIO.setup(dataPin, GPIO.IN)
  
      if None != self.switchPin:
          GPIO.setup(switchPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  </code></pre>
  <p>I added a &quot;host&quot; variable, into which I pass the leg class:</p>
  <pre><code>def __init__(self, clockPin, dataPin, switchPin=None, rotaryCallback=None, switchCallback=None, host=None, rotaryBouncetime=250, switchBouncetime=300):
      # persist values
      self.clockPin = clockPin
      self.dataPin = dataPin
      self.switchPin = switchPin
      self.rotaryCallback = rotaryCallback
      self.switchCallback = switchCallback
      self.rotaryBouncetime = rotaryBouncetime
      self.switchBouncetime = switchBouncetime
  
      # My Change
      self.host = host
  
      #setup pins
      GPIO.setup(clockPin, GPIO.IN)
      GPIO.setup(dataPin, GPIO.IN)
  
      if None != self.switchPin:
          GPIO.setup(switchPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  </code></pre>
  <p>The modified constructor would be called like so:</p>
  <pre><code>self.encoder = KY040(self.clockPin, self.dataPin, rotaryCallback=self.rotaryChange, host=self)
  </code></pre>
  <p>O'Hanlon's callback now passes the host along:</p>
  <pre><code>def _clockCallback(self, pin):
          # My change
          self.rotaryCallback(pin, self.host)
  </code></pre>
  <p>My new callback:</p>
  <pre><code>def rotaryChange(pin, host):
      host.clickedOnce = True
  </code></pre>
  <p>Unfortunately, after making sure the modified code is installed with the setup script, it doesn't seem to acknowledge my new additions. I run my program and receive the follwing error:</p>
  <pre><code>    Traceback (most recent call last):
      File &quot;ctf.py&quot;, line 18, in &lt;module&gt;
        LR = leg.leg(lr_chan, lr_max, lr_park, lr_clk, lr_data);
      File &quot;/home/[user]/hexacrescentapod/leg.py&quot;, line 47, in __init__
        self.encoder = KY040(self.clockPin, self.dataPin, 
      rotaryCallback=self.rotaryChange, host=self)
      TypeError: __init__() got an unexpected keyword argument 'host'
  </code></pre>