Python:使用getter或;“私人”;属性设置器?

Python:使用getter或;“私人”;属性设置器?,python,python-3.x,getter-setter,private-members,Python,Python 3.x,Getter Setter,Private Members,假设我有一个类NamedObject,它有一个属性name。现在,如果我必须使用setter,我首先必须定义一个getter(我想是吧?),如下所示: 现在我想知道,在setter中,我应该使用self.\u name还是self.name,getter还是实际属性?当设置名称时,我会选择ofc。需要使用\u name,但是当我进入setter时呢?例如: @name.setter def name(self, value): if self._name != str(value): #

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

现在我想知道,在setter中,我应该使用
self.\u name
还是
self.name
,getter还是实际属性?当设置名称时,我会选择ofc。需要使用
\u name
,但是当我进入setter时呢?例如:

@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)

使用哪一个,为什么使用一个而不是另一个,这真的很重要吗?

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

使用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)

那么你就患上了“太多Java”综合症。Java开发人员必须编写这种东西,因为如果以后有必要将行为添加到x的设置或获取中,则必须重新编译类外对x的所有访问。但在Python中,最好保持简单,只将x定义为实例变量,仅在需要添加某种设置或获取行为时才转换为属性。请参阅和。

如果您的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所做的只是返回self.\ux,只需直接访问内部变量。

Paul已经回答得很好了

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

如果您设想某个特定的类很可能被您自己或其他人重写/扩展,那么尽早使用getter/setter可能会有助于减少以后用于重构的时间。尽管如此,我还是同意“保持简单”的观点:由于运行时成本和阅读/编码工作,请尽量少用下面的内容

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


这确实违反了雅格尼原则。然而,如果您确实为更广泛的受众发布代码,“过度工程化”通常是可取的。库从增加的灵活性和预见性中获益。

在Python中,通常根本不使用getter和setter。为什么不使用呢?为什么它们会存在呢?O.O我要求的每个人都告诉我使用它们,每个人都告诉我不要使用它们。@Mahi在你确实有理由使用它们时使用它们-例如,你想做一些事情,而不仅仅是直接赋值和读取属性的值(例如验证)。你通常首先只使用实例属性,然后,当您认为必须添加一些操作/控件来获取/设置属性时,可以将其更改为属性,这样您就可以以向后兼容的方式改进代码。添加不起任何作用的随机getter/setter只会编写更多的代码,而不提供任何类型的信息隐藏或功能。@Amber Yeah抱歉,这是我在那里(主要帖子)提出的一个坏例子,但在我的实际代码中,setter上有15行代码,getter上只有一行。我是否应该使用getter和setter?请阅读我在主要帖子上的第二条评论。我来自C++端,不是java,但我猜它们差不多一样。实际上,我的setter中有15行代码,为了回答这个问题,我只写了一个简单的例子。因此,这再次没有回答我的实际问题,但我想我应该责备自己给出了一个糟糕的示例代码:从简单示例中得到的是Python中使用属性的传统智慧:“在需要之前不要这样做。”如果你的getter所做的都是
返回self.\u name
,然后只需在setter中访问self.\u name,并避免不必要的函数调用。如果您以后还需要向getter添加行为,并且如果此行为在setter中非常重要,那么您可能离setter代码足够近,可以追踪到对
self.\u name
的直接引用。
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