有时我想写一个带有实例变量的类,这些实例变量一方面应该被初始化在 __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的实例化对象至少会是一致的。
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
我觉得使用属性可以更好地更新你的变量。
我觉得使用属性可以更好地更新你的变量,在 https:/stackoverflow.coma192926533863847。 可读性是由sthenault提出的,作为为什么实例变量不应该被声明在 __init__
.
据我所知,这根植于PEP 8,这就是为什么pylint抱怨违规的原因--而我从不选择B。
sthenault还建议在以下情况下不进行分配 __init__
就像progmatico在我的问题下面的评论中所做的那样,对应的是我的C版本。
虽然我希望有一个优雅的技巧来规避这种情况,但我暂时将 C 版视为 "最 pythonic"。如果以后有人想出了我要找的这种神奇的解决方法,我会把接受的答案换掉。