Python: 将 class 成员函数传递给另一个 class 的回调
Python: Passing a class member function to another class's callback
我可以将 class A 传递给 class B,以便 B 可以 运行 使用 A 的成员函数进行回调吗?
我正在尝试为我正在构建的机器人编写 Python 腿 class。我使用 Raspberry Pi 作为主计算机,并使用 Martin O'Hanlon 的 KY040 旋转编码器库 KY040 来检测腿的每 1/4 圈。为此,我观察了几次点击中的第一个,短暂休眠,停止伺服,现在已经实现了 1/4 旋转。在独立的非线程代码中,这工作正常,但创建 class 一直是一个挑战。
详情:
线程哨兵循环监视布尔值 (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
访问 pwm 控制器以激活电机,并将 quarterTurn 重置为 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
诀窍是 O'Hanlon 的 class 已经穿线了。一方面方便,另一方面也让我的class变得复杂。 KY040 使用回调函数提供反馈,但在我的 class 中使用它是我的麻烦之源。
我需要回调来修改我腿中的一个布尔值class,但此函数仅由 KY040 class 调用,它试图将自身传递给函数。
def rotaryChange(self, pin):
self.clickedOnce = True
由于代码是开源的(谢谢你,O'Hanlon),我想我可以修改 KY040 的构造函数,让我把我的腿 class 传进去,这样我就可以修改正确的数据。
O'Hanlon 的原始构造函数:
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)
我添加了一个“主机”变量,我将腿传递到其中 class:
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)
O'Hanlon 的回调现在传递给主机:
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 <module>
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'
乍一看,您的新回调似乎缺少 self
字段?
原来的函数是
def rotaryChange(self, pin):
self.clickedOnce = True
但是你的实现是:
def rotaryChange(pin, host):
host.clickedOnce = True
如果这个函数位于 class 中,它需要有一个 self
参数
由于您的措辞,这有点令人困惑。您实际上是想像您所说的那样传递 class ,还是像您看起来那样传递 class 的 instance要做什么? rotaryChange
定义在哪个class?
无论如何,看起来您实际上想要做的是将 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
传递给构造函数,一切都会起作用。
我可以将 class A 传递给 class B,以便 B 可以 运行 使用 A 的成员函数进行回调吗?
我正在尝试为我正在构建的机器人编写 Python 腿 class。我使用 Raspberry Pi 作为主计算机,并使用 Martin O'Hanlon 的 KY040 旋转编码器库 KY040 来检测腿的每 1/4 圈。为此,我观察了几次点击中的第一个,短暂休眠,停止伺服,现在已经实现了 1/4 旋转。在独立的非线程代码中,这工作正常,但创建 class 一直是一个挑战。
详情:
线程哨兵循环监视布尔值 (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
访问 pwm 控制器以激活电机,并将 quarterTurn 重置为 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
诀窍是 O'Hanlon 的 class 已经穿线了。一方面方便,另一方面也让我的class变得复杂。 KY040 使用回调函数提供反馈,但在我的 class 中使用它是我的麻烦之源。
我需要回调来修改我腿中的一个布尔值class,但此函数仅由 KY040 class 调用,它试图将自身传递给函数。
def rotaryChange(self, pin):
self.clickedOnce = True
由于代码是开源的(谢谢你,O'Hanlon),我想我可以修改 KY040 的构造函数,让我把我的腿 class 传进去,这样我就可以修改正确的数据。
O'Hanlon 的原始构造函数:
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)
我添加了一个“主机”变量,我将腿传递到其中 class:
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)
O'Hanlon 的回调现在传递给主机:
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 <module>
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'
乍一看,您的新回调似乎缺少 self
字段?
原来的函数是
def rotaryChange(self, pin):
self.clickedOnce = True
但是你的实现是:
def rotaryChange(pin, host):
host.clickedOnce = True
如果这个函数位于 class 中,它需要有一个 self
参数
由于您的措辞,这有点令人困惑。您实际上是想像您所说的那样传递 class ,还是像您看起来那样传递 class 的 instance要做什么? rotaryChange
定义在哪个class?
无论如何,看起来您实际上想要做的是将 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
传递给构造函数,一切都会起作用。