【发布时间】:2017-07-06 23:58:11
【问题描述】:
我是 Python 新手(目前为止很喜欢它),但在 C++ 和 C# 等 OO 语言方面拥有多年经验,并认为自己是一名强大的 OO 设计师。
我的理解是 Python 并不严格强制执行私有对象属性,但按照惯例,人们期望如果您使用下划线命名属性,他们将知道不要在类外访问它。好吧,够公平的。
我的问题:如果一个对象包含“私有”对象并且我将它返回给调用者,我是否应该制作一个副本以便他们不会搞砸?还是 Python 会自动复制?
# My Channel class has a dictionary of capabilities
class Channel(object):
def __init__(self):
self._capabilities = dict()
如果我执行以下操作,调用者是否可以通过弄乱返回的字典来弄乱我的功能?
@property
def capabilities(self):
return self._capabilities
或者我应该这样做并返回一份副本以保护自己?
@property
def capabilities(self):
# I'm assuming that this creates a new copy of the dictionary
return dict(self._capabilities)
我猜 Python 返回一个引用,以便调用者确实可以弄乱我的私人字典(或列表,或其他),所以我最好先复制一份。
【问题讨论】:
-
你可以使用
@capabilities.getter来指定一个getter函数。您可以做的是在该方法中引发异常,因此人们知道最好不要尝试阅读它。 -
这完全取决于。这是语义。如果您需要他们能够修改对象,则返回一个副本。 Python 对所有可变对象使用引用,因此它将返回与 C++ 中的 shared_ptr 有效相似的内容(即使在 None 上也会调用 Py_IncrRef)。通常,
_method表示类型是“受保护的”,它被认为是内部的和实现相关的,但没有严格执行。__method表示直接类之外的任何调用者都有名称修改,因此它最类似于“私有”。这些是指导方针。 -
"或者 Python 会自动复制吗?" - 与 C++ 不同,Python 几乎从不进行隐式复制。
-
如果内部状态取决于该对象的完整性,但它应该是“只读的”,那么您可能需要一个不带 setter 的 getter 来返回副本。如果您担心实现细节(例如,设置一个值会更新依赖于实现的数据库记录),您可能希望返回没有任何副本的现有对象,但仍然建议其他人不要使用
_method触及实现. -
Python 通过引用传递所有内容(不是真的,而是使用 C# 术语...),但有些结构是可变的,有些则不是。您无需为非可变结构制作副本,因为外部没有任何东西可以改变您的内部属性指向的状态。但是,对于可变结构,如果您希望您的类的用户会修改它们,您将需要创建副本(甚至是深层副本)。
标签: python class properties