如何处理 Python 中的选项参数? (只能是一组值的参数)

How to handle option-arguments in Python? (arguments that can only be of a set of values)

由于我缺乏术语,我很难提出问题。我不是在询问具有默认值的关键字参数。我的问题是关于如何处理只能有一组值的参数值,以及如何优化代码可读性和防止重复。

例如看这个函数:

def foo(opt='something'):

   if opt == 'something':
      ret = dowhatever()

   elif opt == 'somethingelse':
      ret = dowhateverelse()

   else:
      raise UnrecognisedArgumentException(opt)

return ret

在我看来,这很丑陋。它基本上是 python 中不太好看的 java-switch 翻译。出现的一个问题是当案例在案例相关代码之间有公共代码(重复)时,我想避免这种情况。如果我要避免这种情况,我会写:

def foo(opt='something'):
   if opt not in ['something', 'something_else']:
      raise UnrecognisedArgumentException

   if opt == 'something':
      ret = do_whatever()

   elif opt == 'something_else':
      ret = do_whatever_else()

   do_something_universal(ret)

   if opt == 'something':
      ret = do_whatever_afterwards()

   elif opt == 'something_else':
      ret = do_whatever_else_afterwards()

return ret

这个更丑。有没有更好的方式来编写这样的代码?

我正在重新打开这个问题(之前作为 ) 为了解决两个之间有共同代码的具体问题 相关的类似案例的块。这涉及到上下文管理器的思想。 在这里,我们定义了两个不同的上下文管理器,并存储它们dict; case-statement-replacement 服务于 select 我们将使用哪个上下文管理器。

import contextlib

# Step 1: Define the context managers. Usingcontextlib.contextmanager for
# simplicity, but you can define a class with `__enter__` and `__exit__`
# methods as well.

@contextlib.contextmanager
def Something():
    yield do_whatever()
    do_whatever_afterwards()


@contextlib.contextmanager
def SomethingElse():
    yield do_whatever_else()
    do_whatever_else_afterwards()


# Step 2: Map your selectors to the context managers
cms = {
    'something': Something,
    'something_else': SomethingElse
}


# Step 3: Select a context manager and handle attempts to select a non-existent one
opt = ...  # 'something' or 'something_else'
try:
    cm = cms[opt]
except KeyError:
    raise UnrecognisedArgumentException(opt)

# Step 4: Run your universal code in the correct context
with cm() as x:
    do_something_universal(x)