Python factory method with external function
我已经阅读过这个关于工厂方法的讨论,并且有一个备用的构造函数用例。
我的班级如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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应该是:
一个@classmethod,这看起来有点奇怪,因为你不会把它叫做Foo._process_bar()。
类Foo之外但在同一个.py文件中的一种方法。我会同意的,但看起来有点奇怪。这些方法是否始终可用于Foo的实例,而不管它是如何实例化的?(例如,如果它被保存到一个泡菜中,然后重新加载呢?可能类外的方法将不可用!)
一个@staticmethod?(见1)。这看起来很奇怪)
还有别的吗?(但不是这个!)
- 如果process只是使它用在from_data,本地的功能。另外,我去一个模块级功能。你能在进出口精心制作的问题?
- 你认为为什么制作它一@staticmethod会奇怪?只是将它和它在一个def _process_bar(bar):from_data()cls._process_bar(bar)呼叫。
"正确的解决方案"取决于您的需求…
如果函数(_process_bar需要访问类Foo或当前的子类……,那么您需要一个classmethod,它应该被称为cls._process_bar(),而不是Foo._process_bar()。
如果函数不需要访问类本身,但您仍然希望能够在子类中重写它(iow:您希望基于类的多态性),那么您需要一个staticmethod。
否则你只需要一个简单的函数。这个函数的代码存在的地方是不相关的,而您的导入问题是其他方面的。
此外,您可能(或不,取决于具体的用例)希望使用回调函数(可能带有默认值)来实现更大的灵活性,例如:
1 2 3 4 5 6 7 8 9
| 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是一个私有功能,因此用户根本不需要访问它。换句话说,您的第三个案例应该只将_process_bar定义为from_data内部的局部函数,以完全隐藏它。您所提议的将是另一个将功能更改为公共功能的场景。
- 我不会在from_data中定义它,因为即使这是它唯一使用的地方,每次调用from_data时它都会被重新定义。最好只定义一次,可能是Foo中的"私有"静态方法。在功能上,这与模块级函数相同,只是在Foo中命名,以指示它主要在哪里使用。
- @巴库鲁:是的,不一样。wrt/将函数设置为from_data的局部,这只是使函数不稳定,没有好的理由。
- @Chepner很好,函数定义不是一个昂贵的操作(因为代码已经编译好了)。它只需要创建一个结构并增加代码对象的引用计数),这样点就不会真正占用大部分时间。不管怎样,我想说的最重要的一点是,如果OP使用了一个私有函数,那么您应该保持它的私有性,然后只添加扩展。
- @Brunodesthuilliers有非常简单的假设,您可以测试它,即使它是本地定义的。关联是,它不访问由顶级函数定义的其他局部变量(如果是这样的话,您无论如何都不能在其他地方定义它,而不会显著改变它的逻辑)。当然,这不是您通常想要做的事情,而是说它使函数不稳定是错误的。