实现选择标志的 Pythonic 方式

Pythonic way to implement a selection flag

我在一个 Python 模块上工作,其中超过 3/4 的函数提供了 6 个选项的选择,并且相应地表现不同。1

我的目标是使这个参数的使用尽可能简单、明显和可读,以及(尽管不太重要)它的实现。

实现这样一个标志的最pythonic方式是什么?

在我看来,我有 3 个选择:

1.为每个组件使用字符串标识符(当前解决方案):
+:使用简单易读,无需额外导入,classes,实现细节
-:字符串比较,不灵活,用户必须知道字符串(没有编辑器帮助)

# in module/__init__.py
E_X = 'e_x'
E_Y = 'e_y'
...

# in module/whatever.py:
def do_sg(args, comp):
    if comp == E_X:
        set_some_state_for_ex()
        res = calc_sg_with_ex(args)
    elif comp == E_Y:
        ...
    return res

# usage
from module.whatever import do_sg
res = do_sg(args, 'e_r')

2:使用模块范围的常量:
+:文字定义,编辑器提示
-: 更晦涩的用法,命名空间污染(避免使用更晦涩的名字),导入所有组件并不容易

# in module/__init__.py
E_X_COMP = 1
E_Y_COMP = 2
...

# in module/whatever.py, implementation v1
from . import *
def do_sg(args, comp):
    if comp == E_X_COMP:
        set_some_state_for_e_x()
        res = calc_sg_with_e_x(args)
    elif comp == E_Y_COMP:
        ...
    return res

# usage ( (1) may be used this way as well)
import module   # or from module import E_X_COMP, E_Y_COMP, ...
from module.whatever import do_sg
res = do_sg(args, module.E_X_COMP)

# or more obscurely:
res = do_sg(args, 0)

3: 使用枚举 class:
+:封闭的文字定义,比常量更明显的用法,更好的编辑器提示,类型提示
-:比字符串标识符更模糊的实现、模块依赖、更多的导入和对象

# in module/__init__.py
from enum import Enum
class component(Enum):
    e_x = 1
    e_y = 2
    ...

# in module/whatever.py, implementation v1
from . import component
def do_sg(args, comp):
    if comp is component.e_x:
        res = calc_sg_with_e_x(args)
    elif comp is component.e_y:
        ...
    return res

# usage
from module import component
from module.whatever import do_sg
res = do_sg(args, component.e_x)

4: 其他选项?

还有没有其他我没有考虑的方法?


1:更具体的说,这个模块是计算电磁场的分量,选择的是应该考虑哪个分量——可以是E的x、y、z分量和B场。由于各种原因,矢量实施将无法正常工作。

这很有趣,因为我喜欢谈论代码风格。我不知道你到底想做什么,但它似乎以一种简洁的方式实现 switch 。如果我是你,我不会使用任何 (global) 常量。他们总是降低代码的可读性。

一种使代码更具可读性的方法,我认为您可以将 if-else 块定义为函数并直接使用函数而不是使用外部范围常量进行分支。例如:

# in module/whatever.py, implementation v1
from . import *
class do_sg:
    @classmethod
    def e_x(args):
        set_some_state_for_e_x()
        res = calc_sg_with_e_x(args)
        return res

    @classmethod
    def e_y(args):
        ...
        return res

# usage
from module.whatever import do_sg
res = do_sg.e_x(args)

Enum正是为这类问题而创建的。它们也应被视为常量,因此适当的命名将有所帮助:

class Component(Enum):
    E_X = 1
    E_Y = 2

并在使用中;

from module import Component
from module.whatever import do_sg
res = do_sg(args, Component.E_X)