Python:将类成员函数传递给另一个类的回调

问题描述 投票:0回答:2

我可以将类 A 传递到类 B 中,以便 B 可以使用 A 的成员函数运行回调吗?

我正在尝试为我正在构建的机器人编写一个 Python 腿部类。我使用 Raspberry Pi 作为主计算机,并使用 Martin O'Hanlon 的 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
访问 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 的类已经是线程化的。一方面,它很方便,另一方面,它使我的课程变得更加复杂。 KY040 使用回调函数来提供反馈,但在我的课堂上使用它是我的麻烦根源。

我需要回调来修改我的leg类中的布尔值,但该函数仅由KY040类调用,该类尝试将自身传递到该函数中。

def rotaryChange(self, pin):
    self.clickedOnce = True

由于代码是开源的(谢谢你,O'Hanlon),我想我可以修改KY040的构造函数,让我将我的腿类传递给它,这样我就可以修改正确的数据。

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)

我添加了一个“主机”变量,将腿部类传递到其中:

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'
python callback raspberry-pi robotics
2个回答
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
。这意味着您可以恢复对库代码的所有更改。

do
需要将回调方法定义为正确的方法,并以

self

作为第一个参数。但仅此而已。然后你可以将 rotaryCallback=self.rotaryChange 传递给构造函数,一切都会正常工作。

    
乍一看,您的新回调似乎缺少 

self

1
投票

原来的功能是


def rotaryChange(self, pin): self.clickedOnce = True

但是你的实现是:

def rotaryChange(pin, host):
    host.clickedOnce = True

如果这个函数位于类内部,它需要有一个

self
 参数


© www.soinside.com 2019 - 2024. All rights reserved.