Class 设计:优雅地初始化和更新实例变量
Class design: Initializing and updating instance variables elegantly
有时我想写一个带有实例变量的class,一方面应该在__init__
中初始化,但另一方面也可以通过不同的函数更新(function_1
- function_3
) 在某些事件发生后从内部或从外部。
更新函数都依赖于相同的输入参数,但在初始化和后续更新中的工作方式相同。它们可能是 class 的成员(@staticmethod
或不是)或从某个包导入的实用函数。
为了后面的更新,"meta"更新函数(update_member_variables
)显然应该是一个过程,i。 e. return 什么都没有,只是修改成员变量作为副作用。
但是,对于初始化,它最好是一个纯函数和 return 变量的值,以便可以将它们分配给 __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,但是由于所有针对 __init__
之外的成员变量声明的警告,我通常坚持使用 C 或 D,尽管它们看起来臃肿笨重。
有没有更好的办法解决这种情况?也许在盒子外面?或者已经是A-D中最"elegant"或最干净的了?
相关问题:
在中回答了类似的问题,但是update_number
只适合初始化。接受的答案代码就像我的 D,但没有 update_member_variables
.
在 中回答了另一个相关问题。总的来说,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
我觉得使用 属性 可以更好地更新变量。
在 中,sthenault 给出了可读性作为实例变量不应在 __init__
之外声明的原因。
据我所知,这植根于 PEP 8,这就是 pylint 抱怨违规的原因——而我从不选择 B。
sthenault 还建议 None-assignments in __init__
,就像 progmatico 在我的问题下面的评论中所做的那样,这对应于我的版本 C.
虽然我希望有一个优雅的技巧来以某种方式绕过这种情况,但我暂时将 C 视为 "most pythonic"。如果以后有人想出我正在寻找的这种神奇的解决方案,我会切换接受的答案。
有时我想写一个带有实例变量的class,一方面应该在__init__
中初始化,但另一方面也可以通过不同的函数更新(function_1
- function_3
) 在某些事件发生后从内部或从外部。
更新函数都依赖于相同的输入参数,但在初始化和后续更新中的工作方式相同。它们可能是 class 的成员(@staticmethod
或不是)或从某个包导入的实用函数。
为了后面的更新,"meta"更新函数(update_member_variables
)显然应该是一个过程,i。 e. return 什么都没有,只是修改成员变量作为副作用。
但是,对于初始化,它最好是一个纯函数和 return 变量的值,以便可以将它们分配给 __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,但是由于所有针对 __init__
之外的成员变量声明的警告,我通常坚持使用 C 或 D,尽管它们看起来臃肿笨重。
有没有更好的办法解决这种情况?也许在盒子外面?或者已经是A-D中最"elegant"或最干净的了?
相关问题:
在update_number
只适合初始化。接受的答案代码就像我的 D,但没有 update_member_variables
.
在 中回答了另一个相关问题。总的来说,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
我觉得使用 属性 可以更好地更新变量。
在 中,sthenault 给出了可读性作为实例变量不应在 __init__
之外声明的原因。
据我所知,这植根于 PEP 8,这就是 pylint 抱怨违规的原因——而我从不选择 B。
sthenault 还建议 None-assignments in __init__
,就像 progmatico 在我的问题下面的评论中所做的那样,这对应于我的版本 C.
虽然我希望有一个优雅的技巧来以某种方式绕过这种情况,但我暂时将 C 视为 "most pythonic"。如果以后有人想出我正在寻找的这种神奇的解决方案,我会切换接受的答案。