Python类的最佳实践

5
我有一些代码,大致如下:
class Foo:
    def __init__(self, a, b, c=None):
        self.bar = a
        if c:
            self.data = self.calc(b, c)
    def calc(self, bat, baz):
        """calculates some stuff that feels like should belong with the instance of `Foo`"""
  1. 在我的__init__中放置代码是否不好?

  2. 如果我有一个方法生成了一些与类实例相关的数据,那么是更好的实践让用户调用该方法并存储数据,还是让一个实例变量在实例化时存储它?

之所以提出问题2,是因为我有这样一个类,可以从某个json文件生成所有内容,所以这个类只需要一个实例变量和一堆方法吗?这应该不是一个类吗?我总是认为类只有一个实例变量是不好的实践,但另一方面,我有一组函数都操作同一个json文件,所以它们感觉应该属于某种混合结构。

编辑:关于问题2,如果其中一些方法需要基于已初始化的数据和计算出的数据生成数据。那么在上面的示例中,假设我(用户)计算了d = 2 * a + b,因为这对我很重要。然后我想做另一个计算,理论上如果给它d会更快。那么这个方法看起来像new_calc(self, d)。当我最初计算它时,我应该将d存储在类中,然后不再要求用户提供它,还是让他们更加负责呢?


3
只有一个要点:如果 cNone,你应该将 self.data 设置为一个合理的默认值。同时请注意,对于空列表、空元组、空集合、空字典、空字符串和数值零(整数、浮点数或十进制数),bool(c) 可能会被求值为 False - bruno desthuilliers
@brunodesthuilliers 当然没错。我可能制作了一个不太好的实例,这不太好... 哎呀 - Nate Stemen
如果您正在使用Python 2.x,您需要从object继承以获得一个“新式”类,它将正确支持计算属性和super()调用。 - bruno desthuilliers
2
我记得在某个地方读到过,良好的面向对象设计旨在通过外部代码最小化方法序列/依赖性的需求 - 即*记得在调用g()之前调用f()。根据计算成本和可能性,d最终可能需要,在初始化时可以考虑使用缓存的属性w。 - JL Peyret
1个回答

8
在我的init函数中放置代码有什么不好吗?
不会有问题。但如果它执行了复杂的操作,请将代码分解为一个函数/方法,就像您在calc中所做的那样。只是我建议,如果该方法的唯一调用者是构造函数,则使用_calc而不是calc。这样,您向类的用户发出信号,他们不应自己调用_calc
一个小问题:
if c:
   self.data = self.calc(b, c)

我对这段代码持谨慎态度,因为如果c为None(或0或False),self.data仍未设置。因此,所有其余的方法都必须检查data属性是否存在。更好的做法可能是编写:

self.data = self.calc(b, c) if c is None else None

或者你可以将对 None 的检查放入 calc 方法中,并使构造函数中的那一行代码变为:

self.data = self.calc(b, c)

是否最好的做法是让用户调用该方法?

我认为这取决于具体的用例。如果每个实例表示特定的数据集,并且没有必要将一个数据集换成另一个数据集,那么我会说构造函数更适合完成这个任务。这样,数据由实例封装得很好,用户在不应该更改数据时不能犯愚蠢的错误。


1
calc 设为私有,正如 @brunodesthuilliers 指出的那样,确保 self.dat 被设置为某个值。感谢你的回答! - Nate Stemen

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