3

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

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

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

现在我想知道,在 setter 中,我应该使用self._nameor self.name,getter 还是实际属性?设置名称时,I 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

4 回答 4

3

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

于 2012-11-18T19:17:13.280 回答
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,只需直接访问内部变量。

于 2012-11-18T19:49:50.977 回答
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

于 2012-11-18T19:31:43.937 回答
0

保罗已经回答得很好。

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

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

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

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

于 2012-11-19T12:08:54.423 回答