我经常遇到这个问题而且我从来不知道最好的解决方法是什么。
假设我有一个类,其中一个属性是列表。该列表存储在内部,而不是直接访问列表,而是要求用户通过类提供的一组方法与列表进行交互。考虑下面的代码示例:
from validation.check import Check
class Validator(object):
"""
Class used to perform validation.
"""
def __init__(self):
self._checks = []
def add_check(self, check):
"""
Add the given check to the validator.
:param check: Check instance.
:type check: :class:`validation.check.Check`
:raises TypeError: When given value is not a validation.Check
"""
if not isinstance(check, Check):
msg = 'Check item must be type "{0}". Got "{1}"'
msg = msg.format(Check.__name__, type(check).__name__)
raise TypeError(msg)
self._checks.append(check)
@property
def checks(self):
"""
Get validator checks.
"""
return self._checks
在这种情况下,add_check
方法会在将值添加到列表之前对值进行类型检查,但您可以在add_check
方法中添加所有类型的额外功能。
checks
属性允许用户检查检查列表。但是,它还允许用户在不使用add_check
方法的情况下修改检查列表。例如:
validator = Validator()
validator.checks.append('BogusValue')
现在我的checks
列表中的值无效,因为绕过了add_check
方法。什么是解决这个问题的最好,也是最蟒蛇的方式?
有些人建议退回内部列表的副本。
@property
def checks(self):
"""
Get validator checks.
"""
return list(self._checks)
在这种情况下,修改副本不会影响checks
内部存储的Validator
列表。我可以看到这是如何解决问题的,但我认为在某些情况下可能会引起混淆。
有些人建议您返回tuple
或创建只读列表:
import collections
class ReadOnlyList(collections.Sequence):
def __init__(self, items):
super(ReadOnlyList, self).__init__()
self._items = items
def __getitem__(self, index):
return self._items[index]
def __len__(self):
return len(self._items)
从Validator.checks
属性返回只读列表会阻止用户直接修改checks
列表。
def checks(self):
"""
Get validator checks.
"""
return ReadOnlyList(self._checks)
如果我遇到创建自定义列表对象的麻烦,为什么不将类型检查构建到自定义列表对象中?例如:
import collections
class Checks(collections.MutableSequence):
def __init__(self, items):
self._items = []
for index, item in enumerate(items):
self.insert(index, item)
def _validate_item(self, item):
if not isinstance(item, Check):
msg = 'List item must be type "{0}". Got "{1}"'
msg = msg.format(Check.__name__, type(item).__name__)
raise TypeError(msg)
def __getitem__(self, index):
return self._items[index]
def __setitem__(self, index, item):
self._validate_item(item)
self._items[index] = item
def __delitem__(self, index):
del self._items[index]
def __len__(self):
return len(self._items)
def insert(self, index, item):
self._validate_item(item)
self._items.insert(index, item)
然后我可以完全删除add_check
方法,因为类型检查是内置于Checks
对象的。
class Validator(object):
"""
Class used to perform validation.
"""
def __init__(self):
self._checks = Checks()
@property
def checks(self):
"""
Get validator checks.
"""
return self._checks
最后,有些人认为上述所有内容都是过度的,而且文档齐全的代码应该足以阻止用户以非预期的方式添加检查。
也许它们都是有效的解决方案?在这种情况下,我在选择方法并坚持下去时遇到了很多麻烦。如果有人对这个问题有强烈的感受,我很乐意听到你的想法。
非常感谢。