处理类实例化参数组合的最Pythonic方式是什么?

3
假设我有一个叫Foo的类:
class Foo(object):
    @staticmethod
    def get_a(b, c):
        if not b or not c:
            raise ValueError("Invalid params!")
        return b + c

    def __init__(self, a=None, b=None, c=None):
        if not a:
            a = Foo.get_a(b, c)
        self.a = a

用户可以使用包含“a”或同时包含“b”和“c”的类。如果提供了a,则忽略“b”和“c”。
哪种做法更好:当提供所有三个参数时出现错误(确保程序员知道正在使用哪个)还是将其放入文档中,说明如果提供a,则忽略“b”和“c”?
一方面,出现错误更加明确,这是Pythonic的(“明确胜于隐式”)。另一方面,接受任何有效的方法更实际(“虽然实用性胜过纯洁性”)。

可能是重复的问题:http://stackoverflow.com/questions/24457819/optional-parameters-certain-combination-of-them-required - matsjoyce
@matsjoyce:不是很确定,在创建类的实例方面不是这样。 - Martijn Pieters
虽然 FOO(b,c)Foo(Foo.get_a(b,c)) 更容易输入,但并不清楚它是否优于简单的 Foo(b+c)。我相信你的实际代码更加复杂,但请考虑一下是否真的是 Foo 的责任提供一种将 bc 组合成 a 的方法。 - chepner
为了更明确地表达问题,我更改了标题以提及类。 - Temuz
@chepner - 这只是一个例子。它对b和c进行操作,不一定像简单的b + c那样简单。公平的观点-您需要考虑它是否首先属于Foo。 - Temuz
1个回答

6

我会为该类提供一个独立的classmethod工厂:

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

    @classmethod
    def from_b_and_c(cls, b, c):
        return cls(b + c)

这是真正的显式选项;您可以创建Foo(a),或者使用Foo.from_b_and_c(b, c)来生成具有非常不同参数的实例。这立即记录了参数是如何分开的;要么您只从a创建一个实例,要么您同时从bc创建一个实例。
这是一种常见的模式;如果您有多种方法来生成实例,请以类方法的形式提供额外的工厂方法。
例如,您可以使用以下方式生成datetime.date()类:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接