Как реализовать следующий код C в Python?(typedef, enums и switch) - PullRequest
0 голосов
/ 20 марта 2019

У меня есть следующая часть кода в C:

typedef enum {
    CAN_NORMAL_MODE = 0x00,
    CAN_SLEEP_MODE = 0x01,
    CAN_INTERNAL_LOOPBACK_MODE = 0x02,
    CAN_LISTEN_ONLY_MODE = 0x03,
    CAN_CONFIGURATION_MODE = 0x04,
    CAN_EXTERNAL_LOOPBACK_MODE = 0x05,
    CAN_CLASSIC_MODE = 0x06,
    CAN_RESTRICTED_MODE = 0x07,
    CAN_INVALID_MODE = 0xFF
} CAN_OPERATION_MODE;

//more code here in the middle...

d = something 
switch (d) {
    case CAN_NORMAL_MODE:
        mode = CAN_NORMAL_MODE;
        break;
    case CAN_SLEEP_MODE:
        mode = CAN_SLEEP_MODE;
        break;
   // more cases here, not shown for readability
    default:
        mode = CAN_INVALID_MODE;
        break;
}

Здесь d - это байт, который я читаю из других источников. Оператор switch находится внутри другой функции, и там есть больше кода, но я не думаю, что это нужно показывать, поскольку он не имеет ничего общего с этой частью.

Моя проблема: я пытаюсь перевести этот код в Python, по причинам, чтобы он синтаксически сходен с исходным кодом C (то есть я не не хочу, чтобы код Python был радикально другим, поэтому другой человек, который работал с исходным кодом C, может легко понять и использовать код Python). Я не уверен, как реализовать функциональность в этом фрагменте кода на языке Python, не выполняя бесконечный поток операторов if-elif ... else . Я думаю, что должен быть более простой (pythonic) способ сделать это, но я не уверен, как реализовать операторы typedef , enum и switch в Python , Я прочитал несколько способов реализации предложения enum , создающего класс с псевдонимами и значениями в качестве атрибутов, например:

class myClass():
    def __init__(self):
        self.CAN_NORMAL_MODE = 0x00
        self.CAN_SLEEP_MODE = 0x01
        self.CAN_INTERNAL_LOOPBACK_MODE = 0x02
    #etc

Я также натолкнулся на умный способ реализации оператора switch в Python с помощью такой функции (без какого-либо отношения к моей реальной проблеме, просто чтобы показать структуру реализации):

def switch(argument):
    switcher = {
        1: "January",
        2: "February",
        3: "March",
        4: "April",
        5: "May",
        6: "June",
        7: "July",
        8: "August",
        9: "September",
        10: "October",
        11: "November",
        12: "December"
    }
    print switcher.get(argument, "Invalid month")

Но я не могу найти способ объединить эти две вещи простым и понятным способом. Спасибо и хорошего дня!

Ответы [ 3 ]

2 голосов
/ 20 марта 2019
from enum import IntEnum

class CAN_OPERATION_MODE(IntEnum):
    NORMAL_MODE = 0x00
    SLEEP_MODE = 0x01
    INTERNAL_LOOPBACK_MODE = 0x02
    LISTEN_ONLY_MODE = 0x03
    CONFIGURATION_MODE = 0x04
    EXTERNAL_LOOPBACK_MODE = 0x05
    CLASSIC_MODE = 0x06
    RESTRICTED_MODE = 0x07
    INVALID_MODE = 0xFF

    @classmethod
    def _missing_(cls, value):
        return cls.INVALID_MODE

d = something
mode = CAN_OPERATION_MODE(d)

Я бы также удалил _MODE из всех имен перечислений.

1 голос
/ 20 марта 2019

Как насчет словаря? Вы можете назначить каждое значение соответствующему режиму, а затем вызвать его:

modes = {
    0x00 : 'CAN_NORMAL_MODE',
    0x01 : 'CAN_SLEEP_MODE',
    0x02 : 'CAN_INTERNAL_LOOPBACK_MODE',
    0x03 : 'CAN_LISTEN_ONLY_MODE',
    0x04 : 'CAN_CONFIGURATION_MODE',
    0x05 : 'CAN_EXTERNAL_LOOPBACK_MODE',
    0x06 : 'CAN_CLASSIC_MODE',
    0x07 : 'CAN_RESTRICTED_MODE',
    0xFF : 'CAN_INVALID_MODE'
}

d = something
mode = modes[d]
0 голосов
/ 20 марта 2019

Для самого перечисления вы, кажется, делаете это сложнее, чем нужно. Перечисление может быть очень точно сопоставлено с модулем Python, содержащим только набор определений переменных, например:

can_operation_mode.py

CAN_NORMAL_MODE = 0x00
CAN_SLEEP_MODE = 0x01
CAN_INTERNAL_LOOPBACK_MODE = 0x02
CAN_LISTEN_ONLY_MODE = 0x03
CAN_CONFIGURATION_MODE = 0x04
CAN_EXTERNAL_LOOPBACK_MODE = 0x05
CAN_CLASSIC_MODE = 0x06
CAN_RESTRICTED_MODE = 0x07
CAN_INVALID_MODE = 0xFF

Это обеспечивает полезное пространство имен (чего нет в C-перечислениях), а также возможность импортировать эти имена в другой модуль, чтобы использовать их в стиле C, без имени модуля. Конечно, компромисс в том, что они могут быть изменены.

Что касается switch, нет, Python не имеет прямого аналога C switch, по крайней мере, если вы не удовлетворяете виду конструкции if / else if / else, которую вы описываете в вопрос:

other_module.py

import can_operation_mode.*

d = something 
if   d == CAN_NORMAL_MODE:
    mode = CAN_NORMAL_MODE
elif d == CAN_SLEEP_MODE:
    mode = CAN_SLEEP_MODE
// more cases here ...
else:
    mode = CAN_INVALID_MODE

Честно говоря, я не вижу, что с этим не так с точки зрения сохранения синтаксического сходства с исходным C. Это выглядит довольно похоже на меня, вплоть до использования двоеточий.

...