使用 class 方法在 PYTHON class 中分配属性值

Assigning an attribute value in a PYTHON class with class methods

这是一个与设置属性相关的非常基本的问题,我没有找到明确的答案。 我有一个 python class 如下

class circle():
    
    PI = 3.14
    
    def __init__(self,radius):
        self.radius   = radius
        # 1. first way of assigning an atribute
        self.area     = self._area()
        # 2. second way of assigning an attribute (running a method)
        self._squarearea(self.radius,self.area)
        # 3. third way of assigning an attribute
        self.diameter = self._diameter(self.radius)
        
    def _area(self):
        return self.radius * self.PI * self.PI
    
    def _squarearea(self,radius,area):
        self.sqarea = radius * radius * 4 - area
        
    def _diameter(self,radius):
        return self.radius *2

    def giveme4timesradius(self):
        return 4*self.radius

我列出了 4 种分配属性或计算数据的方法。 在我的特定真实示例中,每个方法都执行复杂的计算,这些计算最好为了阅读代码的目的而保持分隔。

我做的每一个作业都有一定的缺点

有多个关于属性和 classes 和教程的 SO 问题(见下文),但我没有在任何地方看到这种比较。 我想我不需要任何 setter 和 getter 因为我只想从一开始就 运行 ,根据倍数条件一些属性将用一些 class 来计算方法或其他。

那么“pythonic”方式有哪些呢?或者其中任何一个?

参考文献:
https://www.toptal.com/python/python-class-attributes-an-overly-thorough-guide
https://realpython.com/lessons/adding-attributes-python-class/
https://www.python-course.eu/python3_class_and_instance_attributes.php
https://medium.com/shecodeafrica/managing-class-attributes-in-python-c42d501c5ee0

正如您所说,第二个选项令人困惑,因为您需要转到方法定义才能了解 class 实例中对新变量的赋值。从这个意义上说,第一个选项更清楚一些,但我仍然想知道该方法的必要输入参数是什么。

然而,第三个选项是错误的,原因有二。第一,你传递了半径但你仍然访问 self.radius,所以这个参数是多余的。第二,即使你使用了参数,它也应该是一个用@staticmethod修饰的静态方法,因为你没有使用class实例(self).

因此,我会使用一个静态方法,它利用它需要的适当输入变量。类似于:

class Circle:

    PI = 3.14

    def __init__(self, radius):
        self.radius = radius
        self.area = self.compute_area(self.radius)

    @staticmethod
    def compute_area(radius):
        return radius * (Circle.PI**2)

这是 @property 装饰器的一个很好的用例。

class Circle():
    
    PI = 3.14
    
    def __init__(self,radius):
        self.radius   = radius
    
    @property
    def area(self):
        return self.radius * (self.PI ** 2)
    
    @property
    def squarearea(self):
        return (self.radius ** 2)  * 4 - self.area
    
    @property
    def diameter(self):
        return self.radius *2
    
    @property
    def giveme4timesradius(self):
        return 4*self.radius

此外,根据我的喜好,我会使用@dataclass:

from dataclasses import dataclass
from typing import ClassVar

@dataclass
class Circle():

    radius: float
    PI: ClassVar[float] = 3.14

    # No need __init__ -> handled by dataclass
    
    @property
    def area(self):
        return self.radius * (self.PI ** 2)
    
    @property
    def squarearea(self):
        return (self.radius ** 2)  * 4 - self.area
    
    @property
    def diameter(self):
        return self.radius *2
    
    @property
    def giveme4timesradius(self):
        return 4*self.radius