[英]How to group functions without side effects?
I have a function with several helper functions. 我有一个带有几个辅助函数的函数。 That's fairly common case. 这是相当普遍的情况。 I want to group them in a common context for readability and I'm wondering how to do it right. 我想将它们分组在一个共同的上下文中以便于阅读,我想知道如何正确地做到这一点。
Simplified example: 简化示例:
def create_filled_template_in_temp(path, values_mapping):
template_text = path.read_text()
filled_template = _fill_template(template_text, values_mapping)
result_path = _save_in_temp(filled_template)
return result_path
def _fill_template(template_text, values_mapping):
...
def _save_in_temp(filled_template):
_, pathname = tempfile.mkstemp(suffix='.ini', text=True)
path = pathlib.Path(pathname)
path.write_text(text)
return path
...
create_filled_template_in_temp(path, values_mapping)
Please note that I don't want the helper methods on the module level because they belong to only one method. 请注意,我不希望模块级别的辅助方法,因为它们只属于一种方法。 Imagine having several such examples as above in the same module. 想象一下,在同一模块中有如上所述的几个这样的例子。 Maany non-public functions on module level. 模块级别的Maany非公共功能。 A mess (and this happens many times). 一团糟(这种情况多次发生)。 Also I'd like to give them context and use the context's name to simplify the naming inside. 另外,我想给它们上下文并使用上下文的名称来简化内部命名。
Solution #0: A module 解决方案#0:一个模块
Just put it in another module: 把它放在另一个模块中:
template_fillers.create_in_temp(path, values_mapping)
Problems: 问题:
Finally this is just too little code to add a module for it. 最后,这只是为它添加模块的代码太少。
Solution #1: A class 解决方案#1:一堂课
Create a class with no __init__
and only one public (by naming convention) method: 创建一个没有__init__
且只有一个公共(通过命名约定)方法的类:
class TemplateFillerIntoTemp:
def run(self, path, values_mapping):
template_text = path.read_text()
filled_template = self._fill_template(template_text, values_mapping)
result_path = self._save_in_temp(filled_template)
return result_path
def _fill_template(self, template_text, values_mapping):
...
def _save_in_temp(self, filled_template):
_, pathname = tempfile.mkstemp(suffix='.ini', text=True)
path = pathlib.Path(pathname)
path.write_text(text)
return path
...
TemplateFillerIntoTemp().run(path, values_mapping)
This is what I did many times in the past. 这就是我过去多次做过的事情。 Problems: 问题:
Solution #2: Static class 解决方案#2:静态类
Take solution #1, add @staticmethod
everywhere. @staticmethod
解决方案#1,到处添加@staticmethod
。 Possibly also ABC metaclass. 可能还有ABC元类。
TemplateFillerIntoTemp.run(path, values_mapping)
Pro: there is a clear indication that this all is instance-independent. 亲:有一个明确的迹象表明这一切都与实例无关。 Con: there's more code. Con:还有更多代码。
Solution #3: Class with a __call__ 解决方案#3:带有__call__的类
Take solution #1, create a __call__
function with the main method, then create on module level a single instance called create_filled_template_in_temp
. 解决方案#1,使用main方法创建__call__
函数,然后在模块级别创建一个名为create_filled_template_in_temp
实例。
create_filled_template_in_temp(path, values_mapping)
Pro: calls like a single function. Pro:调用就像一个函数。 Con: implementation is overblown, not really fit for the purpose. 骗局:实施过于夸张,不适合此目的。
Solution #4: Insert helper functions into main function 解决方案#4:将辅助函数插入main函数
Add them inside. 将它们添加到里面
def create_filled_template_in_temp(path, values_mapping):
def _fill_template(template_text, values_mapping):
...
def _save_in_temp(filled_template):
_, pathname = tempfile.mkstemp(suffix='.ini', text=True)
path = pathlib.Path(pathname)
path.write_text(text)
return path
template_text = path.read_text()
filled_template = _fill_template(template_text, values_mapping)
result_path = _save_in_temp(filled_template)
return result_path
...
create_filled_template_in_temp(path, values_mapping)
Pro: this looks well if total number of lines is small and there are very few helper functions. 亲:如果总行数很少且辅助函数很少,这看起来很好。 Con: it doesn't otherwise. 骗局:否则没有。
Modification of #4: Make inner functions, and also have the function's body be an inner function. 修改#4:创建内部函数,并且函数体也是内部函数。 This has the nice property of still reading top-to-bottom, rather than having the body all the way at the bottom. 这具有仍然从上到下阅读的良好特性,而不是将身体一直放在底部。
def create_filled_template_in_temp(path, values_mapping):
def body():
template_text = path.read_text()
filled_template = fill_template(template_text, values_mapping)
result_path = save_in_temp(filled_template)
return result_path
def fill_template(template_text, values_mapping):
...
def save_in_temp(filled_template):
_, pathname = tempfile.mkstemp(suffix='.ini', text=True)
path = pathlib.Path(pathname)
path.write_text(text)
return path
return body()
(I don't care for the leading underscores, so they didn't survive.) (我不关心领先的下划线,所以他们没有活下来。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.