Python: передача функции-члена класса в обратный вызов другого класса
Могу ли я передать класс A в класс B, чтобы B мог выполнить обратный вызов, используя функцию-член A?
Я пытаюсь написать класс ног Python для робота, которого я строю. Я использую Raspberry Pi в качестве основного компьютера и библиотеку поворотного кодера KY040 Мартина О'Хэнлона KY040 для определения каждого 1/4 поворота ноги. С этой целью я наблюдаю за первым из нескольких щелчков, на короткое время сплю, останавливаю сервопривод, и теперь достигается вращение на 1/4. В автономном коде без резьбы это работает нормально, но создание класса было проблемой.
Спасибо за ваше время.
Детали: резьбовая петля стража следит за логическим значением (quarterTurn), чтобы сигнализировать о необходимости вращения.
def run(self):
print "leg running"
while self._running:
sleep(.0001)
if self.quarterTurn:
print "quarterTurn is: " + str(self.quarterTurn)
self.qTurn(self.quarterCount)
qTurn обращается к контроллеру ШИМ, чтобы активировать двигатели, и сбрасывает четверть-оборот в значение false.
def qTurn(self, quarters):
count = 0
while count < 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
Хитрость в том, что класс О'Хэнлона уже нарезан. С одной стороны, это удобно, с другой - делает мой класс более сложным. KY040 использует функцию обратного вызова для обеспечения обратной связи, но использование этого в моем классе является источником моей проблемы.
Мне нужен обратный вызов для изменения логического значения в моем классе ноги, но эта функция вызывается только классом KY040, который пытается передать себя в функцию.
def rotaryChange(self, pin):
self.clickedOnce = True
Так как код с открытым исходным кодом (спасибо, О'Хэнлон), я подумал, что мог бы изменить конструктор KY040, чтобы я мог передать ему свой класс ноги, чтобы я мог изменить правильные данные.
Оригинальный конструктор О'Хэнлона:
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)
Я добавил переменную "хост", в которую я передаю класс ноги:
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)
Модифицированный конструктор будет называться так:
self.encoder = KY040(self.clockPin, self.dataPin, rotaryCallback=self.rotaryChange, host=self)
Обратный вызов О'Хэнлона теперь передает хосту:
def _clockCallback(self, pin):
# My change
self.rotaryCallback(pin, self.host)
Мой новый обратный звонок:
def rotaryChange(pin, host):
host.clickedOnce = True
К сожалению, после проверки того, что модифицированный код установлен вместе со сценарием установки, он, похоже, не подтверждает мои новые дополнения. Я запускаю свою программу и получаю следующую ошибку:
Traceback (most recent call last):
File "ctf.py", line 18, in
LR = leg.leg(lr_chan, lr_max, lr_park, lr_clk, lr_data);
File "/home/[user]/hexacrescentapod/leg.py", line 47, in __init__
self.encoder = KY040(self.clockPin, self.dataPin,
rotaryCallback=self.rotaryChange, host=self)
TypeError: __init__() got an unexpected keyword argument 'host'
Спасибо, что уделили время на этот длинный вопрос.
2 ответа
Это немного сбивает с толку из-за вашей формулировки. Вы на самом деле пытаетесь передать класс, как вы говорите, или экземпляр этого класса, как вы, кажется, делаете? Какой класс rotaryChange
определяется в?
Во всяком случае, похоже, что вы на самом деле пытаетесь сделать, это пройти self.rotaryChange
в качестве обратного вызова.
Это уже работает, без каких-либо изменений. self.rotaryChange
это связанный метод, то есть он знает, что это self
был, когда он был создан, и пройдет его, когда он будет вызван. Это может быть легче увидеть на примере:
>>> class Spam:
... def eggs(self):
... pass
>>> spam = Spam()
>>> spam
<__main__.Spam at 0x119947630>
>>> spam.eggs
<bound method Spam.eggs of <__main__.Spam object at 0x119947630>>
Обратите внимание, что это связанный метод spam
объект. Когда вы звоните spam.eggs()
, тот spam
объект будет передан как self
аргумент.
Это означает, что вам не нужно передавать host
в, потому что он уже доступен как self
, И, так как это единственное, что вы делаете с host
вам не нужно проходить host
на первом месте. Это означает, что вы можете отменить все свои изменения в коде библиотеки.
Вам нужно определить свой метод обратного вызова как правильный метод, с self
в качестве первого аргумента. Но это все. Тогда вы можете просто пройти rotaryCallback=self.rotaryChange
конструктору, и все будет работать.
На первый взгляд, похоже, что ваш новый обратный вызов отсутствует self
поле?
Первоначальная функция была
def rotaryChange(self, pin):
self.clickedOnce = True
Но ваша реализация:
def rotaryChange(pin, host):
host.clickedOnce = True
Если эта функция находится внутри класса, она должна иметь self
параметр