【问题标题】:Python factory method with external function带有外部函数的 Python 工厂方法
【发布时间】:2014-10-08 12:00:17
【问题描述】:

我已阅读 this SO discussion 关于工厂方法的内容,并且有一个 alternate constructor 用例。

我的班级是这样的:

class Foo(object):
    def __init__(self, bar):
        self.bar = bar

    @classmethod
    def from_data(cls, datafile):
        bar = datafile.read_bar()
        # Now I want to process bar in some way
        bar = _process_bar(bar)
        return cls(bar)

    def _process_bar(self, bar)
        return bar + 1

我的问题是,如果 @classmethod 工厂方法想要在其代码中使用函数,那么该函数 (_proces_bar) 是否应该是:

  1. @classmethod,这似乎有点奇怪,因为你永远不会像 Foo._process_bar() 这样称呼它
  2. Foo 之外但在同一个.py 文件中的方法。我会用这个,但它似乎有点奇怪。这些方法是否总是可用于Foo 的实例,无论它是如何实例化的? (例如,如果将其保存到 Pickle 然后重新加载怎么办?大概类外的方法将不可用!)
  3. @staticmethod? (见 1。这看起来很奇怪)
  4. 还有别的吗? (但不是this!)

【问题讨论】:

  • 如果process只在from_data中使用,则使其成为本地函数。否则,我会使用模块级函数。能否详细说明一下导入问题?
  • 您为什么认为将其设为@staticmethod 会很奇怪?只需用def _process_bar(bar): 声明它,然后用cls._process_bar(bar)from_data() 中调用它。

标签: python coding-style


【解决方案1】:

“正确的解决方案”取决于您的需求......

    1234563不是Foo._process_bar()
  • 如果函数不需要访问类本身,但您仍希望能够在子类中覆盖它(IOW:您需要基于类的多态性),您需要staticmethod

  • 否则你只需要一个普通的函数。此函数的代码所在的位置无关紧要,您的导入问题是正交的。

此外,您可能(或不,取决于您的具体用例)希望使用回调函数(可能带有默认值)来实现更大的灵活性,即:

def process_bar(bar):
   return bar + 1

class Foo(object):
    @classmethod
    def from_data(self, datafile, processor=process_bar):
        bar = datafile.read_bar()
        bar = processor(bar)
        return cls(bar)

【讨论】:

  • 您的最后一个示例与 OP 的示例完全不同。他清楚地表明_process_bar 是一个private 函数,因此用户根本不需要访问它。换句话说,您的第三种情况应该只将 _process_bar 定义为 from_data 内的本地函数以完全隐藏它。您提出的将是另一种将功能更改为公共功能的方案。
  • 我不会在from_data 中定义它,因为即使这是唯一使用它的地方,它也会在您每次调用 from_data 时重新定义。最好定义一次,可能是Foo 中的“私有”静态方法。从功能上讲,这与模块级函数相同,只是在 Foo 内命名空间,以表明主要使用它的位置。
  • @Bakuriu:是的,不一样。 wrt/ 将函数设置为 from_data 的本地函数,它只会使函数无缘无故地无法测试。
  • @chepner 好吧,函数定义不是一项昂贵的操作(因为代码已经编译。它只需要创建一个结构并增加代码对象的引用计数),因此这一点不会t 真的大部分时间都持有。无论如何,我想说的最重要的一点是,如果 OP 使用了私有函数,您应该将其保留为私有,然后才添加扩展。
  • @brunodesthuilliers 通过非常简单的假设,您可以测试它,即使它是本地定义的。假设是它不访问由顶级函数定义的其他局部变量(如果是这种情况,您根本无法在其他地方定义它,而不会显着改变其逻辑)。当然这不是你通常想要做的事情,但说它使函数不可测试是 false
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多