我有一个包含适合以下模板的代码的类:
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.switch
为True
时,我希望执行单行代码而无需在每次迭代时检查self.switch
。当self.switch
为False
时,我希望忽略单行代码,而无需重复检查self.switch
。
我当然考虑编写 f
的两个版本并根据__init__
的值在switch
中选择合适的版本,但重复所有除了一行之外,这段代码感觉不对。
有人能建议一种优雅的方法来解决这个问题吗?也许是一种在初始化时生成适当版本的f
方法的方法?
答案 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_loop
和second_loop
然后在__init__
根据{{1}}:
self.f = self.first_loop
或self.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,举一个例子。)