假设我有一个具有属性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)
使用哪一个,为什么使用另一个?
是否真的重要?答案 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定义为实例变量,并在需要添加某种设置或获取行为时转换为属性。请参阅YAGNI和YAGNI。
答案 3 :(得分:0)
保罗已经回答得很好。
为了完整起见,我想补充一点,使用getter / setter可以更容易地覆盖类。这里有几个含义。
如果您设想某个特定类很可能被您自己或其他人覆盖/扩展,那么在早期使用getter / setter可能会对以后用于重构的时间减少有所帮助。尽管如此,我同意保持简单的观点:由于运行时成本和读取/编码工作量的原因,请谨慎使用以下内容。
如果在getter中完成验证,那么要么直接在setter中使用instance属性,要么提供两个不同的getter name()
和_name()
(或name_already_checked()
),以便两者都可以被覆盖并使用简单的getter而无需在setter中进行验证。这是为了允许扩展快速,无验证类型的getter以及为客户提供的通常的getter。
这确实违反了Paul pointed to的YAGNI原则。但是,如果您确实为更广泛的受众发布代码,则“过度工程”通常是可取的。图书馆受益于更高的灵活性和远见。