Python:在setter中使用getter或“private”属性?

时间:2012-11-18 19:14:06

标签: python python-3.x getter-setter private-members

假设我有一个具有属性NamedObject的班级name。现在如果我不得不使用一个setter,我首先必须定义一个getter(我猜?),如下所示:

class NamedObject:
    def __init__(self, name):
        self.name = name

    @property
    def name(self):
        return self._name

现在我想知道,在二传手中,我应该使用self._name还是self.name,获取者或实际属性?设置名称时,我是ofc。需要使用_name,但是当我进入内部设置器时呢?例如:

@name.setter
def name(self, value):
    if self._name != str(value): # Or should I do 'if self.name != value' ?
        self.doStuff(self._name) # Or doStuff(self.name) ?
        self.doMoreStuff()
        self._name = str(value)

使用哪一个,为什么使用另一个?

是否真的重要?

4 个答案:

答案 0 :(得分:3)

当您的setter是内部接口的一部分时,没有正常理由使用外部接口。我想您可以构建一个您可能想要的场景,但默认情况下,只使用内部变量。

答案 1 :(得分:2)

如果您的getter具有重要的逻辑(如延迟初始化),那么您应该始终通过getter访问。

class Something(object):
    UNINITIALIZED = object()
    LAZY_ATTRS = ('x','y','z')
    def __init__(self):
        for attr in self.LAZY_ATTRS:
            setattr(self, '_'+attr, self.UNINITIALIZED)
    def _get_x(self):
        if self._x is self.UNINITIALIZED:
            self._x = self.doExpensiveInitStuff('x')
        return self._x

但如果你的所有getter都是return self._x,那么只需直接访问内部变量。

答案 2 :(得分:1)

使用getter而不是仅访问内部变量会增加对设置逻辑的另一个函数调用,而在Python中,函数调用很昂贵。如果你这样写:

def _get_x(self):
    return self._x

def _set_x(self, value):
    self._x = value
x = property(fget=_get_x, fset=_set_x)
然后你患上了“Too Much Java”综合症。 Java开发人员来编写这种东西,因为如果以后有必要在x的设置或获取中添加行为,则必须重新编译对类外部x的所有访问。但是在Python中,你最好保持简单,只需将x定义为实例变量,并在需要添加某种设置或获取行为时转换为属性。请参阅YAGNIYAGNI

答案 3 :(得分:0)

保罗已经回答得很好。

为了完整起见,我想补充一点,使用getter / setter可以更容易地覆盖类。这里有几个含义。

如果您设想某个特定类很可能被您自己或其他人覆盖/扩展,那么在早期使用getter / setter可能会对以后用于重构的时间减少有所帮助。尽管如此,我同意保持简单的观点:由于运行时成本和读取/编码工作量的原因,请谨慎使用以下内容。

如果在getter中完成验证,那么要么直接在setter中使用instance属性,要么提供两个不同的getter name()_name()(或name_already_checked()),以便两者都可以被覆盖并使用简单的getter而无需在setter中进行验证。这是为了允许扩展快速,无验证类型的getter以及为客户提供的通常的getter。

这确实违反了Paul pointed to的YAGNI原则。但是,如果您确实为更广泛的受众发布代码,则“过度工程”通常是可取的。图书馆受益于更高的灵活性和远见。