条件执行,无需反复检查条件

时间:2016-12-31 12:40:37

标签: python

我有一个包含适合以下模板的代码的类:

class aClass:

    def __init__(self, switch = False):
        self.switch = switch

    def f(self):
        done = False
        while not done:

            # a dozen lines of code

            if self.switch:
                # a single line of code

            # another dozen lines of code

因此,if语句中的单行代码将从不执行,或者将在所有迭代中执行。实际上,只要初始化对象,就会知道这一点。

self.switchTrue时,我希望执行单行代码而无需在每次迭代时检查self.switch。当self.switchFalse时,我希望忽略单行代码,而无需重复检查self.switch

我当然考虑编写 f两个版本并根据__init__的值在switch中选择合适的版本,但重复所有除了一行之外,这段代码感觉不对。

有人能建议一种优雅的方法来解决这个问题吗?也许是一种在初始化时生成适当版本的f方法的方法?

3 个答案:

答案 0 :(得分:1)

这是一个完全有效的问题。如果不是为了表现,那么为了便于阅读。

在三个单独的方法中提取三个逻辑(在你的条件之前,之内和之后),在f()中只写两个大循环的实现:

def first(self):
    pass

def second(self):
    pass

def third(self):
    pass

def f(self):
    if self.switch:
        while ...:
             self.first()
             self.third()
    else:
         while ...:
            self.first()
            self.second()
            self.third()

如果你想要它更优雅(虽然它取决于品味),你将我的f()的两个分支表达为两个方法first_loopsecond_loop然后在__init__根据{{​​1}}:

分配self.f = self.first_loopself.f = self.second_loop
switch

您可能需要做一些额外的工作来管理打破while循环。

答案 1 :(得分:0)

如果.switch属性不应更改,请尝试在__init__()方法中动态选择循环体:

def __init__(self, switch=False):
    self.switch = switch
    self.__fBody = self.__fSwitchTrue if switch else self.__fSwitchFalse
def f(self):
    self.__done = False
    while not self.__done:
        self.__fBody()
def __fSwitchTrue(self):
    self.__fBodyStart()
    ... # a single line of code
    self.__fBodyEnd()
def __fSwitchFalse(self):
    self.__fBodyStart()
    self.__fBodyEnd()
def __fBodyStart(self):
    ... # a dozen lines of code
def __fBodyEnd(self):
    ... # another dozen lines of code

请记住将多个已定义方法使用的值更改为属性(例如done更改为.__done)。

答案 2 :(得分:0)

在对原始问题的评论中,JohnColeman建议使用exec并提供指向another relevant question的链接。

这是一个很好的建议,我所导致的解决方案是:

_template_pre = """\
def f(self):
    for i in range(5):
        print("Executing code before the optional segment.")
"""

_template_opt = """\
        print("Executing the optional segment")
"""

_template_post = """\
        print("Executing code after the optional segment.")
"""

class aClass:

    def __init__(self, switch = False):
        if switch:
            fdef = _template_pre + _template_opt + _template_post
        else:
            fdef = _template_pre + _template_post
        exec(fdef, globals(), self.__dict__)
        # bind the function
        self.f = self.f.__get__(self)

您可以验证这确实有效:

aClass(switch = False).f()
aClass(switch = True).f()

在得出“pythonic”的结论之前,让我指出这种方法用于我遇到的几个元类配方中,甚至在Python标准库中也是如此(检查the implementation of namedtuple,举一个例子。)