简体   繁体   English

定义在初始化时按顺序计算属性的类的最佳实践

[英]Best practice for defining a class that computes attributes in order when initialized

I would like to define a class that does something like:我想定义一个执行以下操作的类:

Class computer():
    def __init__(self, x):
        # compute first the 'helper' properties
        self.prop1 = self.compute_prop1(x)
        self.prop2 = self.compute_prop2(x)
        # then compute the property that depends on 'helpers'
        self.prop3 = self.compute_prop3(x)

    def compute_prop1(self, x):
        return x
    def compute_prop2(self, x):
        return x*x
    def compute_prop3(self, x):
        return self.prop1 + self.prop2

Then, when I initialize an instance, I get all properties computed in order (first helpers, then everything depending on helpers later):然后,当我初始化一个实例时,我会按顺序计算所有属性(首先是助手,然后是一切取决于助手):

>>> computer = Computer(3)
>>> computer.__dict__
{'prop1': 3, 'prop2': 9, 'prop3': 12}

However, I think there is a better practice of writing this code, for example using decorators.但是,我认为编写此代码有更好的做法,例如使用装饰器。 Could you please give me some hints?你能给我一些提示吗? Thank you!谢谢!

Here's your class using properties instead (with an added method for returning each property):这是您使用属性的类(添加了用于返回每个属性的方法):

Class PropertyComputer:
    def __init__(self, x):
        self._x = x

    @property
    def prop1(self):
        return self._x

    @property
    def prop2(self):
        return self._x * self._x

    @property
    def prop3(self):
        return self.prop1 + self.prop2

    def get_props(self):
        return self.prop1, self.prop2, self.prop3

Design-wise, I believe this is better because:在设计方面,我相信这更好,因为:

  • storing x as an instance variable makes more sense: the point of using objects is to avoid having to pass variables around, especially those that the object itself can keep track of;x存储为实例变量更有意义:使用对象的目的是避免必须传递变量,尤其是那些对象本身可以跟踪的变量;
  • the attribute assignment and its corresponding calculation are bundled together in each property-decorated method: we'll never have to think whether the problem is in the init method (where you define the attribute) or in the compute method (where the logic for the attribute's calculation is laid out).属性赋值及其相应的计算捆绑在每个属性修饰的方法中:我们永远不必考虑问题是在 init 方法(定义属性的地方)还是计算方法(其中的逻辑)属性的计算被列出)。

Note that the concept of "first calculate helpers, then the properties depending on them" does not really apply to this code: we only need to evaluate prop3 if/when we actually need it.请注意,“首先计算帮助程序,然后根据它们计算属性”的概念并不真正适用于此代码:我们只需要在实际需要时评估prop3 If we never access it, we never need to compute it.如果我们从不访问它,我们就永远不需要计算它。

A "bad" side-effect of using properties, compared to your example, is that these properties are not "stored" anywhere (hence why I added the last method):与您的示例相比,使用属性的“坏”副作用是这些属性不会“存储”在任何地方(因此我添加了最后一个方法):

c = PropertyComputer(x=2)
c.__dict__  # outputs {'_x': 2}

Also note that, using decorators, the attributes are calculated on-the-fly whenever you access them , instead of just once in the init method.另请注意,使用装饰器,属性在您访问它们时即时计算,而不是在 init 方法中仅计算一次。 In this manner, property-decorated methods work like methods, but are accessed like attributes (it's the whole point of using them):以这种方式,属性修饰的方法像方法一样工作,但像属性一样访问(这是使用它们的全部意义):

c = PropertyComputer(x=2)
c.prop1  # outputs 2
c._x = 10
c.prop1  # outputs 10

As a side note, you can use functools.cached_property to cache the evaluation of one of these properties, in case it's computationally expensive.作为旁注,您可以使用functools.cached_property来缓存对这些属性之一的评估,以防计算成本很高。

I think the following would be the easiest way to avoid redundancy我认为以下是避免冗余的最简单方法

class computer():
    def __init__(self, x):
        self.prop_dict = self.compute_prop_dict(x)

    def compute_prop_dict(self, x):
        prop1 = x
        prop2 = x*x
        return {'prop1': prop1, 'prop2': prop2, 'prop3': prop1 + prop2}

So anything that would come after instantiation could have access to these helpers via the prop_dict因此,实例化后的任何内容都可以通过prop_dict访问这些助手

But as said by Brian as a comment this order is just a language specification for Python 3.7但正如 Brian 在评论中所说,这个命令只是 Python 3.7 的语言规范

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM