在 Python 中,什么时候修改 self 什么时候返回新实例?

问题描述 投票:0回答:2

我经常进退两难,一个类什么时候应该修改自己,什么时候返回一个新的修改过的实例。

假设我想编写一个简单的序列库。

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)?但是如果我有很多修改对象的方法,就会有很多开销。

python class instance
2个回答
0
投票

这主要取决于你想让用户在你的结构中意识到什么。

一方面,修改

self.seq
确保您保持对结构的完全控制,因为您可以控制访问该字段的方式(例如通过属性)

另一方面,直接返回集合允许用户对其进行任何转换,因此您将无法控制添加到

seq
的内容。如果没有进行正确的检查,它会完全破坏你的类逻辑。


0
投票

通常,对于内置函数,规则是:

  1. 如果类实例在逻辑上是可变的,并且该方法作为变异方法是有意义的,使变异方法(并且它们总是返回

    None
    ,所以不会混淆它们是否返回自己变异,或者变异副本)

  2. 如果类实例在逻辑上是不可变的,你别无选择,所有方法都返回新对象(注意:该类型的新对象;

    rename
    返回一个不相关的
    list
    而不是一个新的
    Seq
    会很奇怪)

Do not 有像基于论证那样返回不同的方法,这是毫无意义的混淆,特别是如果人们按位置传递它;快点,与

obj.rename(xyz, True)
相对的
obj.rename(xyz, False)
是什么意思?这对你来说是更多的工作,对他们来说也是更多的工作,只是不要这样做。

由于您的班级在逻辑上是可变的,请遵循#1 的规则。不要做一堆变体方法,只需定义切片(这样他们就可以为浅拷贝做

myseq[:]
)和/或
copy
方法(
list
提供两者,你也可以)。如果用户想保留原来的东西,他们先复制,然后再改变结果。使其在使用中更加清晰,并避免大量代码重复。

© www.soinside.com 2019 - 2024. All rights reserved.