我经常进退两难,一个类什么时候应该修改自己,什么时候返回一个新的修改过的实例。
假设我想编写一个简单的序列库。
class Seq:
def __init__(self, seq):
self.seq = seq
然后我想重命名序列中的元素,这个方法在Seq中有两个选项:
def rename(lookup):
self.seq = [lookup[e] for e in self.seq]
或
def rename(lookup):
return [lookup[e] for e in self.seq]
我将处理更复杂的结构,例如,如果我正在创建一个图并且我想将它放入唯一的规范(唯一的顶点枚举)形式,它应该将自己放入这种形式还是返回一个新实例。最常见的做法是什么以及何时选择这两个选项?
我的想法是:你必须参与用户最常使用的东西。但这是
def rename(lookup, create_new_instance = False):
if create_new_instance:
return [lookup[e] for e in self.seq]
else:
self.seq = [lookup[e] for e in self.seq]
一个好的做法?
或者我应该只实现两种不同的方法,一种是返回新对象的静态方法,另一种是修改自身的非静态方法?喜欢 list.sort() 和 sorted(list)?但是如果我有很多修改对象的方法,就会有很多开销。
这主要取决于你想让用户在你的结构中意识到什么。
一方面,修改
self.seq
确保您保持对结构的完全控制,因为您可以控制访问该字段的方式(例如通过属性)
另一方面,直接返回集合允许用户对其进行任何转换,因此您将无法控制添加到
seq
的内容。如果没有进行正确的检查,它会完全破坏你的类逻辑。
通常,对于内置函数,规则是:
如果类实例在逻辑上是可变的,并且该方法作为变异方法是有意义的,只使变异方法(并且它们总是返回
None
,所以不会混淆它们是否返回自己变异,或者变异副本)
如果类实例在逻辑上是不可变的,你别无选择,所有方法都返回新对象(注意:该类型的新对象;
rename
返回一个不相关的list
而不是一个新的Seq
会很奇怪)
Do not 有像基于论证那样返回不同的方法,这是毫无意义的混淆,特别是如果人们按位置传递它;快点,与
obj.rename(xyz, True)
相对的obj.rename(xyz, False)
是什么意思?这对你来说是更多的工作,对他们来说也是更多的工作,只是不要这样做。
由于您的班级在逻辑上是可变的,请遵循#1 的规则。不要做一堆变体方法,只需定义切片(这样他们就可以为浅拷贝做
myseq[:]
)和/或copy
方法(list
提供两者,你也可以)。如果用户想保留原来的东西,他们先复制,然后再改变结果。使其在使用中更加清晰,并避免大量代码重复。