这是用于班级建设的合理的软件工程实践吗?

时间:2019-07-11 22:41:30

标签: python class oop class-method

这是写一个类的方法,听起来很合理吗?该类中有一个语法糖@static方法,用于与外界交互?谢谢。

###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

1 个答案:

答案 0 :(得分:2)

回答您的问题和评论,是的,可以编写这样的代码,但我认为这样做没有意义:

class A:
    def __new__(cls, value):
        return cls.meth1(value)

    def meth1(value):
        return value + 1 

result = A(100)
print(result)

# output:
101

您不能存储对类A实例的引用,因为您获得方法结果而不是A实例。因此,将不会调用现有的__init__

因此,如果实例只是计算某些内容并立即将其丢弃,那么您想要的是编写一个简单的函数,而不是一个类。您不在任何地方存储状态。 如果你看的话:

result = some_func(value) 

完全符合人们在阅读时所期望的功能调用。

因此,除非您为此提出了一个很好的用例(我现在不记得了),否则这不是一个好习惯。

与此问题相关的还有文档here,以了解__new____init__的行为。

关于我的回答下方的其他评论:

始终在类中定义__init__来设置(已经)创建的实例的初始状态(属性值)。但是__new__具有自定义对象创建的不同目标。运行__new__时,实例对象尚不存在(它是一个构造函数)。除非您需要类似 singleton 之类的东西,否则在Python中很少需要__new__,比如说A类,当用{{进行调用时,它总是返回与A相同的对象实例。 1}}。普通的用户定义类通常在实例化时返回一个新对象。您可以使用A()内置函数进行检查。另一个用例是当您创建自己的不可变类型的版本(通过子类化)时。因为它是不可变的,所以已经设置了该值,无法在id()或更高版本中更改该值。因此,需要在此之前采取行动,在__init__中添加代码。使用__new__而不返回相同类类型的对象(这是不常见的情况)会导致无法运行__new__的问题。

如果您只是在一个类中对许多方法进行分组,但是在每个实例中仍然没有要存储/管理的状态(您也注意到方法主体中缺少__init__的使用),请考虑不要现在完全使用一个类并组织这些方法,现在在导入的模块或包中已变成无私的函数。因为看起来您正在分组只是为了组织相关代码。

如果因为涉及状态而坚持使用类,请考虑使用不超过5到7个方法将类拆分为较小的类。还可以考虑通过将各个小类分类为各个模块/子模块并使用子类来为它们提供更多的结构,因为一长串简单的小类(无论如何还是函数)在精神上很难遵循。

这与self的使用无关。

总而言之,对返回结果(或无)的函数调用或通过调用类名的对象实例化使用调用的语法。在这种情况下,通常是返回预期类型的​​对象(称为类)。返回方法的结果通常涉及返回不同的类型,这对于类用户而言似乎是意外的。有一个非常接近的用例,其中一些编码器从其方法中返回__new__以允许使用类似火车的语法:

self

最后,如果您不喜欢 my_font = SomeFont().italic().bold() ,请考虑一个别名:

result = A().method(value)

请注意如何在代码中不引用A()实例。 如果您需要参考拆分,请进一步分配:

func = A().method
...
result = func(value)

如果不需要引用A(),那么您可能也不需要实例,并且该类只是将方法分组。你可以写

a = A()
func = a.method
...
result = func(value)

其中无私方法应使用func = A.method result = func(value) 装饰,因为其中不涉及实例。还请注意如何将静态方法转换为类之外的简单函数。

编辑:

我已经建立了一个与您尝试完成的示例类似的示例。对于多步骤过程,也很难判断是否有将结果注入下一方法的方法是最佳选择。因为它们共享某种状态,所以它们彼此耦合,因此也可以更轻松地向彼此注入错误。我假设您想以这种方式在它们之间共享一些数据(这就是为什么要在一个类中设置它们):

因此,这是一个示例类,其中的公共方法通过调用内部方法链来构建结果。所有方法都依赖于对象状态,在这种情况下,尽管获得了用于计算的输入值,但是在这种情况下,@staticmethod仍然如此。

因此,每个方法都使用self来访问状态是有意义的。能够实例化具有不同配置的不同对象也很有意义,因此我在这里看不到self.offset@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)