内部类方法是返回值还是仅修改实例变量?

时间:2012-06-13 14:42:43

标签: python oop instance-variables

我正在创建一个查询构建器类,它将帮助从URL params构建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)接近这个?这只是愚蠢而不是重要的设计决定吗?任何帮助表示赞赏。

4 个答案:

答案 0 :(得分:11)

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

该决定主要用于测试目的。为了进行毛皮测试,可以方便地单独测试每个方法,而无需测试整个对象的状态。但这不适用于这种情况,因为我们讨论的是内部方法,所以你自己决定何时调用该方法,而不是其他对象或其他代码。

答案 1 :(得分:8)

如果您退回任何内容,我建议self。从实例方法返回self对于方法链接很方便,因为每个返回值允许对同一对象进行另一个方法调用:

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

这有时被称为“流利的”#34; API。

但是,虽然Python允许对intstr等不可变类型进行方法链接,但它不会为可变容器的方法提供它,例如listset - 设计 - 所以它可以说不是" Pythonic"为你自己的可变类型做这件事。尽管如此,许多Python库确实具有流畅的#34;的API。

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

答案 2 :(得分:6)

最好返回一个值,因为它允许您将所有属性修改保存在一个位置(__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")

VS。 “制定者版本”:

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以获得清晰度。

答案 3 :(得分:4)

虽然对象的方法通常直接修改其状态,但有时对象可能是自己的“客户端”,并通过(通常)私有访问方法间接访问自身。在Python中,您可以通过使用内置的property()类/函数创建

来轻松完成此操作

这样做可以提供更好的encapsulation及其后续的好处(实现细节的绝缘是主要的)。然而,这样做可能是不切实际的,因为它需要太多额外的代码,并且通常较慢,这可能会对性能造成不利的不可接受的数量 - 因此通常必须在这个理想上进行权衡。