这是 class 构建的可靠软件工程实践吗?
Is this sound software engineering practice for class construction?
这是编写一个 class 的合理且合理的方式吗?其中有一个语法糖 @staticmethod 用于与外部交互?谢谢
###scrip1.py###
import SampleClass.method1 as method1
output = method1(input_var)
###script2.py###
class SampleClass(object):
def __init__(self):
self.var1 = 'var1'
self.var2 = 'var2'
@staticmethod
def method1(input_var):
# Syntactic Sugar method that outside uses
sample_class = SampleClass()
result = sample_class._method2(input_var)
return result
def _method2(self, input_var):
# Main method executes the various steps.
self.var4 = self._method3(input_var)
return self._method4(self.var4)
def _method3(self):
pass
def _method4(self):
pass
回答你的问题和你的评论,是的,可以编写这样的代码,但我认为这样做没有意义:
class A:
def __new__(cls, value):
return cls.meth1(value)
def meth1(value):
return value + 1
result = A(100)
print(result)
# output:
101
您不能存储对 class A 实例的引用,因为您得到的是方法结果而不是 A 实例。因此,不会调用现有的 __init__
。
因此,如果实例只是计算一些东西并立即被丢弃,您需要的是编写一个简单的函数,而不是 class。您没有在任何地方存储状态。
如果你看看它:
result = some_func(value)
看起来完全符合人们阅读时的期望,一个函数调用。
所以不,这不是一个好的做法,除非你想出一个好的用例(我现在不记得了)
与此问题相关的还有文档 here 以了解 __new__
和 __init__
行为。
关于您在我的回答下方的其他评论:
在 class 中定义 __init__
以设置(已经)创建的实例的初始状态(属性值)一直在发生。但是 __new__
具有自定义 对象创建 的不同目标。当__new__
为运行时实例对象还不存在(它是一个构造函数)。 __new__
在 Python 中很少需要,除非你需要像 单例 这样的东西,比如 class A
总是 [=117=当用 A()
调用时,它是(A 的)完全相同的对象实例。正常 user-defined class 通常是 return 实例化的新对象。您可以使用 id()
内置函数进行检查。另一个用例是当您创建自己的不可变类型版本(通过 subclassing)时。因为它是不可变的,所以该值已经设置,并且无法更改 __init__
或之后的值。因此需要在此之前采取行动,在 __new__
内添加代码。使用 __new__
而没有 returning 相同 class 类型的对象(这是 不常见的 情况)有一个额外的问题不是 运行宁__init__
.
如果您只是将许多方法分组到 class 中,但在每个实例中仍然没有 store/manage 的状态(您也注意到缺少 self
使用在方法主体中),考虑根本不使用 class 并将这些方法组织成模块或包中的无私函数以供导入。因为看起来你分组只是为了组织相关代码。
如果因为涉及状态而坚持使用 classes,请考虑将 class 分解为更小的 classes,方法不超过 5 到 7 个。还可以考虑通过将一些小的 classes 分组到各种 modules/submodules 中并使用 subclasses 来给它们更多的结构,因为一个很长的小 classes 列表(或函数)可能在精神上难以理解。
这与 __new__
用法无关。
总而言之,将调用语法用于return作为结果(或None)的函数调用或通过调用class 名称进行对象实例化。在这种情况下,通常是 return 预期类型的对象(被称为 class )。返回方法的结果通常涉及 return 不同的类型,这对 class 用户来说可能看起来出乎意料。有一个接近的用例,一些编码器 return self
从他们的方法中允许 train-like 语法:
my_font = SomeFont().italic().bold()
最后如果你不喜欢result = A().method(value)
,考虑一个别名:
func = A().method
...
result = func(value)
请注意您如何在代码中没有引用 A() 实例。
如果您需要进一步拆分作业的参考:
a = A()
func = a.method
...
result = func(value)
如果不需要对 A() 的引用,那么您可能也不需要该实例,并且 class 只是对方法进行分组。你可以只写
func = A.method
result = func(value)
无私的方法应该用 @staticmethod
修饰,因为不涉及实例。另请注意如何将静态方法转换为 classes.
之外的简单函数
编辑:
我已经设置了一个类似于您要完成的示例。也很难判断将结果注入下一个方法的方法是否是多步骤过程的最佳选择。因为它们共享一些状态,所以它们相互耦合,因此也可以更容易地相互注入错误。我假设您想以这种方式在它们之间共享一些数据(这就是为什么您要在 class 中设置它们):
所以这是一个示例 class,其中 public 方法通过调用一系列内部方法来构建结果。所有方法都依赖于对象状态,self.offset
在这种情况下,尽管获得了用于计算的输入值。
因此,每个方法都使用 self 来访问状态是有道理的。您能够实例化具有不同配置的不同对象也是有道理的,所以我认为 @staticmethod
或 @classmethod
.
在这里没有用
像往常一样在 __init__
中完成初始实例配置。
# file: multistepinc.py
def __init__(self, offset):
self.offset = offset
def result(self, value):
return self._step1(value)
def _step1(self, x):
x = self._step2(x)
return self.offset + 1 + x
def _step2(self, x):
x = self._step3(x)
return self.offset + 2 + x
def _step3(self, x):
return self.offset + 3 + x
def get_multi_step_inc(offset):
return MultiStepInc(offset).result
--------
# file: multistepinc_example.py
from multistepinc import get_multi_step_inc
# get the result method of a configured
# MultiStepInc instance
# with offset = 10.
# Much like an object factory, but you
# mentioned to prefer to have the result
# method of the instance
# instead of the instance itself.
inc10 = get_multi_step_inc(10)
# invoke the inc10 method
result = inc10(1)
print(result)
# creating another instance with offset=2
inc2 = get_multi_step_inc(2)
result = inc2(1)
print(result)
# if you need to manipulate the object
# instance
# you have to (on file top)
from multistepinc import MultiStepInc
# and then
inc_obj = MultiStepInc(5)
# ...
# ... do something with your obj, then
result = inc_obj.result(1)
print(result)
输出:
37
13
22
这是编写一个 class 的合理且合理的方式吗?其中有一个语法糖 @staticmethod 用于与外部交互?谢谢
###scrip1.py###
import SampleClass.method1 as method1
output = method1(input_var)
###script2.py###
class SampleClass(object):
def __init__(self):
self.var1 = 'var1'
self.var2 = 'var2'
@staticmethod
def method1(input_var):
# Syntactic Sugar method that outside uses
sample_class = SampleClass()
result = sample_class._method2(input_var)
return result
def _method2(self, input_var):
# Main method executes the various steps.
self.var4 = self._method3(input_var)
return self._method4(self.var4)
def _method3(self):
pass
def _method4(self):
pass
回答你的问题和你的评论,是的,可以编写这样的代码,但我认为这样做没有意义:
class A:
def __new__(cls, value):
return cls.meth1(value)
def meth1(value):
return value + 1
result = A(100)
print(result)
# output:
101
您不能存储对 class A 实例的引用,因为您得到的是方法结果而不是 A 实例。因此,不会调用现有的 __init__
。
因此,如果实例只是计算一些东西并立即被丢弃,您需要的是编写一个简单的函数,而不是 class。您没有在任何地方存储状态。 如果你看看它:
result = some_func(value)
看起来完全符合人们阅读时的期望,一个函数调用。
所以不,这不是一个好的做法,除非你想出一个好的用例(我现在不记得了)
与此问题相关的还有文档 here 以了解 __new__
和 __init__
行为。
关于您在我的回答下方的其他评论:
在 class 中定义 __init__
以设置(已经)创建的实例的初始状态(属性值)一直在发生。但是 __new__
具有自定义 对象创建 的不同目标。当__new__
为运行时实例对象还不存在(它是一个构造函数)。 __new__
在 Python 中很少需要,除非你需要像 单例 这样的东西,比如 class A
总是 [=117=当用 A()
调用时,它是(A 的)完全相同的对象实例。正常 user-defined class 通常是 return 实例化的新对象。您可以使用 id()
内置函数进行检查。另一个用例是当您创建自己的不可变类型版本(通过 subclassing)时。因为它是不可变的,所以该值已经设置,并且无法更改 __init__
或之后的值。因此需要在此之前采取行动,在 __new__
内添加代码。使用 __new__
而没有 returning 相同 class 类型的对象(这是 不常见的 情况)有一个额外的问题不是 运行宁__init__
.
如果您只是将许多方法分组到 class 中,但在每个实例中仍然没有 store/manage 的状态(您也注意到缺少 self
使用在方法主体中),考虑根本不使用 class 并将这些方法组织成模块或包中的无私函数以供导入。因为看起来你分组只是为了组织相关代码。
如果因为涉及状态而坚持使用 classes,请考虑将 class 分解为更小的 classes,方法不超过 5 到 7 个。还可以考虑通过将一些小的 classes 分组到各种 modules/submodules 中并使用 subclasses 来给它们更多的结构,因为一个很长的小 classes 列表(或函数)可能在精神上难以理解。
这与 __new__
用法无关。
总而言之,将调用语法用于return作为结果(或None)的函数调用或通过调用class 名称进行对象实例化。在这种情况下,通常是 return 预期类型的对象(被称为 class )。返回方法的结果通常涉及 return 不同的类型,这对 class 用户来说可能看起来出乎意料。有一个接近的用例,一些编码器 return self
从他们的方法中允许 train-like 语法:
my_font = SomeFont().italic().bold()
最后如果你不喜欢result = A().method(value)
,考虑一个别名:
func = A().method
...
result = func(value)
请注意您如何在代码中没有引用 A() 实例。 如果您需要进一步拆分作业的参考:
a = A()
func = a.method
...
result = func(value)
如果不需要对 A() 的引用,那么您可能也不需要该实例,并且 class 只是对方法进行分组。你可以只写
func = A.method
result = func(value)
无私的方法应该用 @staticmethod
修饰,因为不涉及实例。另请注意如何将静态方法转换为 classes.
编辑:
我已经设置了一个类似于您要完成的示例。也很难判断将结果注入下一个方法的方法是否是多步骤过程的最佳选择。因为它们共享一些状态,所以它们相互耦合,因此也可以更容易地相互注入错误。我假设您想以这种方式在它们之间共享一些数据(这就是为什么您要在 class 中设置它们):
所以这是一个示例 class,其中 public 方法通过调用一系列内部方法来构建结果。所有方法都依赖于对象状态,self.offset
在这种情况下,尽管获得了用于计算的输入值。
因此,每个方法都使用 self 来访问状态是有道理的。您能够实例化具有不同配置的不同对象也是有道理的,所以我认为 @staticmethod
或 @classmethod
.
像往常一样在 __init__
中完成初始实例配置。
# file: multistepinc.py
def __init__(self, offset):
self.offset = offset
def result(self, value):
return self._step1(value)
def _step1(self, x):
x = self._step2(x)
return self.offset + 1 + x
def _step2(self, x):
x = self._step3(x)
return self.offset + 2 + x
def _step3(self, x):
return self.offset + 3 + x
def get_multi_step_inc(offset):
return MultiStepInc(offset).result
--------
# file: multistepinc_example.py
from multistepinc import get_multi_step_inc
# get the result method of a configured
# MultiStepInc instance
# with offset = 10.
# Much like an object factory, but you
# mentioned to prefer to have the result
# method of the instance
# instead of the instance itself.
inc10 = get_multi_step_inc(10)
# invoke the inc10 method
result = inc10(1)
print(result)
# creating another instance with offset=2
inc2 = get_multi_step_inc(2)
result = inc2(1)
print(result)
# if you need to manipulate the object
# instance
# you have to (on file top)
from multistepinc import MultiStepInc
# and then
inc_obj = MultiStepInc(5)
# ...
# ... do something with your obj, then
result = inc_obj.result(1)
print(result)
输出:
37
13
22