类设计。优雅地初始化和更新实例变量

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

有时我想写一个带有实例变量的类,这些实例变量一方面应该被初始化在 __init__,但另一方面也可以通过不同的函数进行更新(function_1 - function_3),可以在事件发生后从内部更新,也可以从外部更新。

更新函数都依赖于相同的输入参数,但在初始化和之后的更新中工作是一样的。它们可以是类的成员(@staticmethod 或不)或从某个包中导入的实用函数。

对于后面的更新,"元 "更新函数(update_member_variables)显然应该是一个过程,即什么也不返回,只修改成员变量,作为一个副作用,但是,对于初始化来说,它最好是一个纯函数,并返回变量的值,这样它们就可以被分配到 __init__.

这种冲突总是让我经历以下重复代码的循环,声明之外的 __init__None-初始化,但从来没有得到一个满意的解决方案。

from some_utils import function_1, function_2, function_3


# A: duplicate code in update_member_variables
class Class:
    def __init__(self, parameter):
        self._variable_1 = function_1(parameter)
        self._variable_2 = function_2(parameter)
        self._variable_3 = function_3(parameter)

    def update_member_variables(self, parameter):
        self._variable_1 = function_1(parameter)
        self._variable_2 = function_2(parameter)
        self._variable_3 = function_3(parameter)


# B: instance variables declared outside __init__
class Class:
    def __init__(self, parameter):
        self.update_member_variables(parameter)

    def update_member_variables(self, parameter):
        self._variable_1 = function_1(parameter)
        self._variable_2 = function_2(parameter)
        self._variable_3 = function_3(parameter)


# C: boilerplate None-assignments
class Class:
    def __init__(self, parameter):
        self._variable_1 = None
        self._variable_2 = None
        self._variable_3 = None
        self.update_member_variables(parameter)

    def update_member_variables(self, parameter):
        self._variable_1 = function_1(parameter)
        self._variable_2 = function_2(parameter)
        self._variable_3 = function_3(parameter)


# D: back to duplicated code in update_member_variables
class Class:
    def __init__(self, parameter):
        (
            self._variable_1,
            self._variable_2,
            self._variable_3
        ) = self._derive_values(parameter)

    def _derive_values(self, parameter):
        return (
            function_1(parameter),
            function_2(parameter),
            function_3(parameter),
        )

    def update_member_variables(self, parameter):
        (
            self._variable_1,
            self._variable_2,
            self._variable_3
        ) = self._derive_values(parameter)

很想选择B,但由于所有针对成员变量声明的警告都在B之外 __init__,我一般都是坚持用C或D,虽然它们看起来很臃肿,很笨重。

难道就没有更好的方法来解决这种情况吗?也许是跳出框框?还是A-D中已经有了最 "优雅 "或最简洁的一种?

相关的问题。

在... https:/stackoverflow.coma516074413863847。 类似的问题已经回答,但 update_number 只适合初始化。被接受的答案的代码和我的D一样,但没有了 update_member_variables.

https:/stackoverflow.coma206614983863847。 另一个相关问题得到了回答。一般来说,Simeon Visser指出,开发者有责任保证初始化后的对象一致,但也不是严格意义上的无论如何都要坚持这个规则。我的案例是这样一种情况,选择B可以吗?B的实例化对象至少会是一致的。

python oop initialization instance-variables
1个回答
1
投票
class A:
    def __init__(self, parameter):
        self._variable_1 = function_1(parameter)
        self._variable_2 = function_2(parameter)
        self._variable_3 = function_3(parameter)

    @property
    def variable_1(self):
        return self._variable_1

    @variable_1.setter
    def variable_1(self, value):
        self._variable_1 = function_1(value)

    ... so on and so forth for other variables ...

 a = A(parameter1)
 # update based on parameters
 a.variable_1 = parameter2

我觉得使用属性可以更好地更新你的变量。


0
投票

我觉得使用属性可以更好地更新你的变量,在 https:/stackoverflow.coma192926533863847。 可读性是由sthenault提出的,作为为什么实例变量不应该被声明在 __init__.

据我所知,这根植于PEP 8,这就是为什么pylint抱怨违规的原因--而我从不选择B。

sthenault还建议在以下情况下不进行分配 __init__就像progmatico在我的问题下面的评论中所做的那样,对应的是我的C版本。

虽然我希望有一个优雅的技巧来规避这种情况,但我暂时将 C 版视为 "最 pythonic"。如果以后有人想出了我要找的这种神奇的解决方法,我会把接受的答案换掉。

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