Python机器人控制器代码中的SyntaxError

时间:2019-05-26 16:18:14

标签: python python-2.7

我正在将approxeng.input.selectbinder用作机器人控制器, def __init__(self, *requirements, print_events=False, **kwargs): 引发SyntaxError,特别是print_events语句。我不明白为什么。这是给出错误的完整代码:

from functools import reduce
from select import select
from threading import Thread

import approxeng.input.sys as sys
from approxeng.input.controllers import *

EV_KEY = 1
EV_REL = 2
EV_ABS = 3


class ControllerResource:
    """
    General resource which binds one or more controllers on entry and unbinds the event listening thread on exit.
    """

    def __init__(self, *requirements, print_events=True, **kwargs):
        """
        Create a new resource to bind and access one or more controllers. If no additional arguments are supplied this
        will find the first controller of any kind enabled by the library. Otherwise the requirements must be provided
        as a list of ControllerRequirement

        :param requirements:
            ControllerRequirement instances used, in order, to find and bind controllers. If empty this will
            be equivalent to supplying a single unfiltered requirement and will match the first specified controller.
        :param print_events:
            Defaults to False, if set to True then all events picked up by the binder will be printed to stdout. Use
            this when you're trying to figure out what events correspond to what axes and buttons!
        :param kwargs:
            Any addition keyword arguments are passed to the constructors for the controller classes. This is useful
            particularly to specify e.g. dead and hot zone ranges on discovery.
        :raises ControllerNotFoundError:
            If the requirement can't be satisfied, or no requirements are specified but there aren't any controllers.
        """

        self.discoveries = find_matching_controllers(*requirements, **kwargs)
        self.unbind = None
        self.print_events = print_events

    def __enter__(self):
        """
        Called on entering the resource block, returns the controller passed into the constructor.
        """
        self.unbind = bind_controllers(*self.discoveries, print_events=self.print_events)
        if len(self.discoveries) == 1:
            return self.discoveries[0].controller
        else:
            return tuple(discovery.controller for discovery in self.discoveries)

    def __exit__(self, exc_type, exc_value, traceback):
        """
        Called on resource exit, unbinds the controller, removing the listening thread.
        """
        self.unbind()


def bind_controllers(*discoveries, print_events=False):
    """
    Bind a controller or controllers to a set of evdev InputDevice instances, starting a thread to keep those
    controllers in sync with the state of the hardware.

    :param discoveries:
        ControllerDiscovery instances specifying the controllers and their associated input devices
    :param print_events:
        Defaults to False, if set to True then all events picked up by this binder will be printed to stdout
    :return: 
        A function which can be used to stop the event reading thread and unbind from the device
    """

    discoveries = list(discoveries)

    class SelectThread(Thread):
        def __init__(self):
            Thread.__init__(self, name='evdev select thread')
            self.daemon = True
            self.running = True

            self.device_to_controller_discovery = {}
            for discovery in discoveries:
                for d in discovery.devices:
                    self.device_to_controller_discovery[d.fn] = discovery
            self.all_devices = reduce(lambda x, y: x + y, [discovery.devices for discovery in discoveries])

        def run(self):

            for discovery in discoveries:
                discovery.controller.device_unique_name = discovery.name

            while self.running:
                try:
                    r, w, x = select(self.all_devices, [], [], 0.5)
                    for fd in r:
                        active_device = fd
                        controller_discovery = self.device_to_controller_discovery[active_device.fn]
                        controller = controller_discovery.controller
                        controller_devices = controller_discovery.devices
                        prefix = None
                        if controller.node_mappings is not None and len(controller_devices) > 1:
                            try:
                                prefix = controller.node_mappings[active_device.name]
                            except KeyError:
                                pass
                        for event in active_device.read():
                            if print_events:
                                print(event)
                            if event.type == EV_ABS or event.type == EV_REL:
                                controller.axes.axis_updated(event, prefix=prefix)
                            elif event.type == EV_KEY:
                                # Button event
                                if event.value == 1:
                                    # Button down
                                    controller.buttons.button_pressed(event.code, prefix=prefix)
                                elif event.value == 0:
                                    # Button up
                                    controller.buttons.button_released(event.code, prefix=prefix)
                except Exception as e:
                    self.stop(e)

        def stop(self, exception=None):

            for discovery in discoveries:
                discovery.controller.device_unique_name = None
                discovery.controller.exception = exception

            self.running = False

    polling_thread = SelectThread()

    # Force an update of the LED and battery system cache
    sys.scan_cache(force_update=True)

    for device in polling_thread.all_devices:
        device.grab()

    def unbind():
        polling_thread.stop()
        for dev in polling_thread.all_devices:
            try:
                dev.ungrab()
            except IOError:
                pass

    polling_thread.start()

    return unbind

1 个答案:

答案 0 :(得分:0)

为了节省大家的阅读量,以下是该问题的Minimal Reproducable Example

class ControllerResource:

    def __init__(self, *requirements, print_events=True, **kwargs):
        pass

使用Python 3.x可以很好地进行编译(即,您可以无错误地导入它)。在Python 2.x中,这会引发SyntaxError。

原因是该代码使用的是Python 3.x语法。从Python 3.0开始,允许将常规参数(在这种情况下为print_events)出现在varargs参数(在这种情况下为*requirements)之后。有关详细信息和更多示例,请参见PEP 3102

首选解决方案是使用Python 3.x。

使用Python 2.x确实有充分的理由吗? Python 2.x的(延长的)生命终止日期是January 1, 2020,这意味着在该日期之后将不再维护。如果出于某些原因确实必须使用Python 2.x,则应重新排列__init__方法的参数。