Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/reporting-services/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 定义在初始化时按顺序计算属性的类的最佳实践_Python_Python Decorators_Class Properties - Fatal编程技术网

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

Python 定义在初始化时按顺序计算属性的类的最佳实践,python,python-decorators,class-properties,Python,Python Decorators,Class Properties,我想定义一个类,它执行以下操作: 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 'h

我想定义一个类,它执行以下操作:

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
然后,当我初始化一个实例时,我会按顺序计算所有属性(首先是helpers,然后是依赖于helpers的所有内容):


然而,我认为编写这段代码有更好的实践,例如使用decorator。你能给我一些提示吗?谢谢大家!

我认为以下是避免冗余的最简单方法

class computer():
定义初始化(self,x):
self.prop\u dict=self.compute\u prop\u dict(x)
定义计算属性(self,x):
prop1=x
prop2=x*x
返回{'prop1':prop1,'prop2':prop2,'prop3':prop1+prop2}
因此,实例化之后出现的任何内容都可以通过
prop\u dict


但是正如Brian在评论中所说,这个顺序只是Python 3.7的语言规范,我认为下面是避免冗余的最简单的方法

class computer():
定义初始化(self,x):
self.prop\u dict=self.compute\u prop\u dict(x)
定义计算属性(self,x):
prop1=x
prop2=x*x
返回{'prop1':prop1,'prop2':prop2,'prop3':prop1+prop2}
因此,实例化之后出现的任何内容都可以通过
prop\u dict


但正如Brian在评论中所说,此顺序只是Python 3.7的语言规范,这里是使用属性的类(添加了返回每个属性的方法):

就设计而言,我认为这更好,因为:

  • x
    存储为实例变量更有意义:使用对象的目的是避免传递变量,尤其是对象本身可以跟踪的变量
  • 属性赋值及其相应的计算在每个属性修饰的方法中捆绑在一起:我们永远不必考虑问题是在init方法(定义属性的地方)还是在compute方法(属性计算的逻辑被安排的地方)中
请注意,“首先计算助手,然后计算依赖于它们的属性”的概念并不真正适用于此代码:我们只需要在实际需要时计算
prop3
。如果我们从不访问它,我们就不需要计算它

与您的示例相比,使用属性的一个“坏”副作用是这些属性没有“存储”在任何地方(因此我添加了最后一个方法):

还要注意的是,使用decorator,无论何时访问属性,都会动态计算属性,而不是在init方法中只计算一次。通过这种方式,属性修饰方法的工作方式类似于方法,但访问方式类似于属性(这就是使用它们的全部意义):


作为旁注,您可以使用缓存对其中一个属性的计算,以防计算开销过大。

以下是使用属性的类(添加了用于返回每个属性的方法):

就设计而言,我认为这更好,因为:

  • x
    存储为实例变量更有意义:使用对象的目的是避免传递变量,尤其是对象本身可以跟踪的变量
  • 属性赋值及其相应的计算在每个属性修饰的方法中捆绑在一起:我们永远不必考虑问题是在init方法(定义属性的地方)还是在compute方法(属性计算的逻辑被安排的地方)中
请注意,“首先计算助手,然后计算依赖于它们的属性”的概念并不真正适用于此代码:我们只需要在实际需要时计算
prop3
。如果我们从不访问它,我们就不需要计算它

与您的示例相比,使用属性的一个“坏”副作用是这些属性没有“存储”在任何地方(因此我添加了最后一个方法):

还要注意的是,使用decorator,无论何时访问属性,都会动态计算属性,而不是在init方法中只计算一次。通过这种方式,属性修饰方法的工作方式类似于方法,但访问方式类似于属性(这就是使用它们的全部意义):


作为补充说明,您可以使用缓存这些属性之一的计算,以防计算开销过大。

请注意,维护字典的插入顺序只是Python 3.7+的语言规范。如果您使用的是较旧版本的Python,请注意不要依赖于此。如果以后需要
prop1
prop2
,此代码看起来不错。如果不这样做,您可以在调用时直接使用它们,比如
self.prop=self.compute(self.compute\u prop1(x),self.compute\u prop2(x))
prop1=;prop2=。。。;self.prop=self.compute(prop1,prop2)
(分号应该是换行符,但注释中的代码格式是有限的…)请注意,维护字典的插入顺序只是Python 3.7+的语言规范。如果您使用的是较旧版本的Python,请注意不要依赖于此。如果以后需要
prop1
prop2
,此代码看起来不错。如果不这样做,您可以在调用时直接使用它们,比如
self.prop=self.compute(self.compute\u prop1(x),self.compute\u prop2(x))
prop1=;prop2=。。。;self.prop=self.compute(prop1,prop2)
(分号应该是换行符,但注释中的代码格式是有限的…)
>>> computer = Computer(3)
>>> computer.__dict__
{'prop1': 3, 'prop2': 9, 'prop3': 12}
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
c = PropertyComputer(x=2)
c.__dict__  # outputs {'_x': 2}
c = PropertyComputer(x=2)
c.prop1  # outputs 2
c._x = 10
c.prop1  # outputs 10