这是用于班级建设的合理的软件工程实践吗? [英] Is this sound software engineering practice for class construction?

查看:39
本文介绍了这是用于班级建设的合理的软件工程实践吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是写类的一种合理而合理的方法吗,其中有一种语法糖@staticmethod用于外部交互?

Is this a plausible and sound way to write a class where there is a syntactic sugar @staticmethod that is used for the outside to interact with? Thanks.

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


推荐答案

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

Answering to both your question and your comment, yes it is possible to write such a code but I see no point in doing it:

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 __

You can't store a reference to a class A instance because you get your method result instead of an A instance. And because of this, an existing __init__will not be called.

因此,如果实例只是计算并获得立即丢弃,您想要的是编写一个简单的函数,而不是一个类。您不在任何地方存储状态。
而且,如果您看一下:

So if the instance just calculates something and gets discarded right away, what you want is to write a simple function, not a class. You are not storing state anywhere. And if you look at it:

result = some_func(value) 

完全符合人们在阅读函数调用时的期望。

looks exactly to what people expect when reading it, a function call.

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

So no, it is not a good practice unless you come up with a good use case for it (I can't remember one right now)

与此问题相关的另一个是文档此处以了解 __ new __ __ init __ 行为。

Also relevant for this question is the documentation here to understand __new__ and __init__ behaviour.

关于下面的其他评论我的答案:

Regarding your other comment below my answer:

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

defining __init__ in a class to set the initial state (attribute values) of the (already) created instance happens all the time. But __new__ has the different goal of customizing the object creation. The instance object does not exist yet when __new__is run (it is a constructor function). __new__ is rarely needed in Python unless you need things like a singleton, say a class A that always returns the very same object instance (of A) when called with A(). Normal user-defined classes usually return a new object on instantiation. You can check this with the id() builtin function. Another use case is when you create your own version (by subclassing) of an immutable type. Because it's immutable the value was already set and there is no way of changing the value inside __init__ or later. Hence the need to act before that, adding code inside __new__. Using __new__ without returning an object of the same class type (this is the uncommon case) has the addtional problem of not running __init__.

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

If you are just grouping lots of methods inside a class but there is still no state to store/manage in each instance (you notice this also by the absence of self use in the methods body), consider not using a class at all and organize these methods now turned into selfless functions in a module or package for import. Because it looks you are grouping just to organize related code.

如果由于涉及状态而坚持学习班级,请考虑将班级分为不超过五个的小班级到7种方法。还可以考虑通过将各个模块/子模块中的一些小类进行分组并使用子类来为它们提供更多的结构,因为一长串的小类(无论如何还是函数)在精神上很难遵循。

If you stick to classes because there is state involved, consider breaking the class into smaller classes with no more than five to 7 methods. Think also of giving them some more structure by grouping some of the small classes in various modules/submodules and using subclasses, because a long plain list of small classes (or functions anyway) can be mentally difficult to follow.

这与 __ new __ 的使用无关。

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

In summary, use the syntax of a call for a function call that returns a result (or None) or for an object instantiation by calling the class name. In this case the usual is to return an object of the intended type (the class called). Returning the result of a method usually involves returning a different type and that can look unexpected to the class user. There is a close use case to this where some coders return self from their methods to allow for train-like syntax:

 my_font = SomeFont().italic().bold()

最后,如果您不喜欢 result = A()。method(value),请考虑一个别名:

Finally if you don't like result = A().method(value), consider an alias:

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

请注意,如何在代码中不引用A()实例。
如果您需要进一步拆分引用,请执行以下操作:

Note how you are left with no reference to the A() instance in your code. If you need the reference split further the assignment:

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

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

If the reference to A() is not needed then you probably don't need the instance too, and the class is just grouping the methods. You can just write

func = A.method
result = func(value)

其中无私方法应该用 @staticmethod 修饰,因为其中不涉及任何实例。还要注意如何将静态方法转换为类之外的简单函数。

where selfless methods should be decorated with @staticmethod because there is no instance involved. Note also how static methods could be turned into simple functions outside classes.

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

I have setup an example similar to what you are trying to acomplish. It is also difficult to judge if having methods injecting results into the next method is the best choice for a multistep procedure. Because they share some state, they are coupled to each other and so can also inject errors to each other more easily. I assume you want to share some data between them that way (and that's why you are setting them up in a class):

所以这是一个示例类,其中有一个公共方法通过调用内部方法链来构建结果。所有方法都取决于对象状态,在这种情况下,尽管获得输入值,但仍取决于对象状态 self.offset

So this an example class where a public method builds the result by calling a chain of internal methods. All methods depend on object state, self.offset in this case, despite getting an input value for calculations.

因此,每个方法都使用self来访问状态是有意义的。能够实例化具有不同配置的不同对象也很有意义,因此在这里我看不到 @staticmethod @classmethod

Because of this it makes sense that every method uses self to access the state. It also makes sense that you are able to instantiate different objects holding different configurations, so I see no use here for @staticmethod or @classmethod.

初始实例配置通常在 __ init __ 中完成。

Initial instance configuration is done in __init__ as usual.

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






输出:


Outputs:

37
13
22

这篇关于这是用于班级建设的合理的软件工程实践吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆