在Python中重置类的首选方法

2024-04-26 05:46:34 发布

您现在位置:Python中文网/ 问答频道 /正文

基于this post on CodeReview

我有一节课 Foo在Python(3)中,当然包括一个__init__()方法。这个类触发几个提示并执行它的操作。假设我想重置Foo,这样我就可以重新开始这个过程。

首选的实现方式是什么?

再次调用__init__()方法

def reset(self):
    self.__init__()

或者创建一个新实例?

def reset(self):
    Foo()

我不确定如果多次调用reset,创建Foo的新实例是否会留下任何可能影响性能的内容。另一方面,如果不是所有属性都在__init__()中定义(重新定义),那么__init__()可能会有副作用。

有没有更好的方法?


Tags: 实例方法self定义fooiniton过程
2条回答

您可以将使用的实例保存在类属性中。 无论何时要重置类,请将新实例重新指派给该属性。 下面是我将如何实现这种方法:

class Foo:
    instance = None    # The single instance

    def __init__(self, ...):
        # Initialize the instance if Foo.instance does not exist, else fail
        if type(self).instance is None:
            # Initialization
            type(self).instance = self
        else:
            raise RuntimeError("Only one instance of 'Foo' can exist at a time")

    @classmethod
    def reset(cls):
        cls.instance = None        # First clear Foo.instance so that __init__ does not fail
        cls.instance = Foo(...)    # Now the initialization can be called

然后,您可以通过简单地引用Foo.instance来访问实例。

我选择将reset作为类方法,因此由@classmethod修饰。 使用这个decorator,可以通过调用Foo.reset()重置实例,并且cls参数将自动传递给该方法。

我更喜欢这种方法(或多或少是一种单例模式)而不是您建议的方法,因为在您的情况下,似乎有一个Foo的实例是合乎逻辑的,因为您希望重置它。 因此,我发现“强制”使用单个实例是相当直观的。

另一方面,可以在类之外有一个实例,并使用一个reset实例方法,定义如下:

def reset(self):
    self.__init__()

但这可能不太管用。 假设您想在__init__方法之外设置属性。 调用__init__不会重置这些属性。 因此,您的实例将不会按预期重置。 现在,如果您持有一个实例并将其重新分配给一个全新的实例,那么您肯定它将是绝对干净的。

关于您所说的“创建新实例”,这或多或少是我选择的,但问题是在哪里存储它。 我认为在课堂上保持温暖是有意义的。

顺便说一句,这个解决方案不应该有任何性能问题(如“内存泄漏”),因为一次只引用一个Foo实例,而创建一个新实例将取消对前一个实例的引用。

两者都是正确的,但语义的实现方式不同。

为了能够重置一个实例,我会编写这个(我更喜欢从__init__调用一个自定义方法,而不是相反的方法,因为__init__是一个特殊的方法,但这主要是一个口味问题):

class Foo:
    def __init__(self):
        self.reset()
    def reset(self):
        # set all members to their initial value

你这样使用它:

Foo foo      # create an instance
...
foo.reset()  # reset it

从头开始创建新实例实际上更简单,因为该类不必实现任何特殊方法:

Foo foo      # create an instance
...
foo = Foo()  # make foo be a brand new Foo

如果旧实例不在其他任何地方使用,它将被垃圾回收

这两种方法都可以用于normal类,其中所有初始化都在__init__中完成,但对于在创建时使用__new__自定义的特殊类(例如不可变类),则需要第二种方法。


但请注意,以下代码:

def reset(self):
    Foo()

不会做你想做的事:它只会创建一个新的实例,并立即删除它,因为它将在方法的末尾超出范围。即使是self = Foo()也只会设置本地引用,这样在方法结束时,本地引用也会超出作用域(并销毁新实例)。

相关问题 更多 >

    热门问题