内部类方法应该返回值还是只修改实例变量



我正在创建一个查询生成器类,它将有助于从URL参数构造mongodb的查询。 除了使用基本的语言结构和使用 django 内置的模型之外,我从未做过太多面向对象的编程,也没有设计过供我以外的人使用的类。

所以我有这个QueryBuilder

class QueryHelper():
    """
    Help abstract out the problem of querying over vastly
    different dataschemas.
    """
    def __init__(self, collection_name, field_name, params_dict):
        self.query_dict = {}
        self.params_dict = params_dict
        db = connection.get_db()
        self.collection = db[collection_name]
    def _build_query(self):
        # check params dict and build a mongo query
        pass

现在在_build_query中,我将检查params_dict并填充query_dict,以便将其传递给 mongo 的 find() 函数。在这样做时,我只是想知道是否有一种绝对正确的方法,即_build_query是否应该返回字典或是否应该修改self.query_dict。 由于它是一种内部方法,我认为只需修改self.query_dict就可以了。 有没有一种正确的方法(pythonic)方法来解决这个问题?这是否只是愚蠢的,不是一个重要的设计决策?任何帮助,不胜感激。

最好返回一个值,因为它允许您将所有属性修改保存在一个地方(__init__ )。此外,这使得以后更容易扩展代码;假设您要重写子类中的_build_query,则重写方法可以只返回一个值,而无需知道要设置哪个属性。下面是一个示例:

class QueryHelper(object):
    def __init__(self, param, text):
        self._param = param
        self._query = self._build_query(text)
    def _build_query(self, text):
        return text + " and ham!"
class RefinedQueryHelper(QueryHelper):
    def _build_query(self, text):
        # no need to know how the query object is going to be used
        q = super(RefinedQueryHelper, self)._build_query()
        return q.replace("ham", "spam")

与"二传手版本"相比:

class QueryHelper(object):
    def __init__(self, param, text):
        self._param = param
        self._build_query(text)
    def _build_query(self, text):
        self._query = text + " and ham!"
class RefinedQueryHelper(QueryHelper):
    def _build_query(self, text):
        # what if we want to store the query in __query instead?
        # then we need to modify two classes...
        super(RefinedQueryHelper, self)._build_query()
        self._query = self._query.replace("ham", "spam")

如果选择设置属性,则可能需要调用该方法_set_query为清楚起见。

修改self.query_dict是完全可以的,因为面向对象编程的整个思想是方法可以修改对象的状态。只要对象在方法完成后处于一致状态,就可以了。_build_query是内部方法这一事实并不重要。您可以选择在创建对象时调用 _build_query after __init__以构造查询。

该决定主要出于测试目的。出于测试目的,可以方便地单独测试每个方法,而不必测试整个对象的状态。但这不适用于这种情况,因为我们谈论的是内部方法,因此您独自决定何时调用该方法,而不是其他对象或其他代码。

如果你返回任何东西,我建议self.从实例方法返回self对于方法链接很方便,因为每个返回值都允许对同一对象进行另一个方法调用:

foo.add_thing(x).add_thing(y).set_goal(42).execute()

这有时被称为"流畅"API。

然而,虽然 Python 允许对不可变类型(如 intstr)进行方法链接,但它并没有为可变容器(如 listset)的方法提供方法链 - 通过设计 - 所以可以说它不是"Pythonic"为你自己的可变类型这样做。尽管如此,许多Python库确实具有"流畅"的API。

缺点是这样的 API 会使调试更加困难。由于您执行整个语句或不执行任何语句,因此无法在语句中的中间点轻松看到对象。当然,我通常发现print完全适合调试 Python 代码,所以我会在我感兴趣的任何返回值的方法中抛出一个print

虽然对象的方法通常直接修改其状态,但有时对象成为自己的"客户端",并通过(通常)私有访问方法间接访问自身是有利的。在 Python 中,您可以使用内置的 property() 类/函数轻松完成此操作。

这样做可以提供更好的封装和随之而来的好处(与实现细节的隔离是主要因素)。但是,这样做可能不切实际,因为它需要太多额外的代码并且通常速度较慢,这可能会对性能产生不可接受的不利影响 - 因此必须经常需要针对此理想进行权衡。

最新更新