简体   繁体   English

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

[英]Assigning an attribute value in a PYTHON class with class methods

This is a very basic question relating to setting attributes that I don't find a definitive answer to.这是一个与设置属性有关的非常基本的问题,我没有找到明确的答案。 I have a python class as follows我有一个 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

I listed 4 ways to assign attributes or calculate data.我列出了 4 种分配属性或计算数据的方法。 In my particular real example every of the methods performs complicated calculations that are better to keep compartmentalised for reading code purposes.在我的特定真实示例中,每种方法都执行复杂的计算,这些计算最好为了阅读代码目的而保持分隔。

Every of the assignments I do comes with certain disadvantages我做的每一项任务都有一些缺点

  • way 1: self.area = self._area() .方式1: self.area = self._area() The reader does not now in the init method how many variables takes area to make the calculation.读者现在不知道在init方法中有多少变量需要面积来进行计算。 A class method is run but the reader would have to dig into the code to see what is calculated and how运行 class 方法,但读者必须深入研究代码以查看计算内容以及如何计算

  • way 2: self._squarearea(self.radius,self.area) The reader in this case does not know what the function does, not even if the function sets a new attribute as it is the case.方式 2: self._squarearea(self.radius,self.area)在这种情况下,读者不知道 function 做了什么,即使 function 设置了新属性也是如此。 On the contrary at least it is indicated that radius and area are passed to the function.相反,至少表明半径和面积被传递给 function。 Actually the two variables passed are only an indication since within the class method all the class attributes are available.实际上,传递的两个变量只是一个指示,因为在 class 方法中,所有 class 属性都可用。

  • way 3: self.diameter = self._diameter(self.radius) Here the reader knows that the radius is pass and also knows that an attribute is assigned (diameter)方式3: self.diameter = self._diameter(self.radius)这里读者知道半径是pass,也知道分配了一个属性(直径)

  • way 4: A last way can be thought offering the consumer of the class to call a method giveme4timesradius() , but this is inconvenient since I want all to be previously calculated.方式 4:最后一种方式可以考虑为 class 的消费者提供调用方法giveme4timesradius() ,但这很不方便,因为我希望所有内容都预先计算。 And it would have to be calculated every time it is called.每次调用时都必须计算它。

There are multiple SO questions about attributes and classes and tutorials (see some bellow), but I did not see this comparison anywhere.关于属性、类和教程有多个 SO 问题(见下文),但我在任何地方都没有看到这种比较。 I think I don't need any setter and getter because I just want to run all from the start, depending on multiples conditions some attributes will be calculated with some class methods or others.我想我不需要任何 setter 和 getter,因为我只想从头开始运行,根据倍数条件,某些属性将使用一些 class 方法或其他方法计算。

So what of the ways is the "pythonic" way?那么“pythonic”方式有哪些方式? Or any of those?还是其中任何一个?

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

The second option is confusing, as you said, because you would need to go to the method definition to understand there is an assignment to a new variable in the class instance.正如您所说,第二个选项令人困惑,因为您需要 go 到方法定义才能了解 class 实例中的新变量的赋值。 The first option is somewhat clearer in that sense, but I would still like to know what is the necessary input arguments to that method.从这个意义上说,第一个选项更加清晰,但我仍然想知道该方法的必要输入 arguments 是什么。

The third option however is wrong for two reasons.然而,第三种选择是错误的,原因有两个。 One, you pass the radius but you still access self.radius, so the argument is redundant.一,你传递了半径,但你仍然访问 self.radius,所以这个参数是多余的。 Second, even if you use the argument, it's supposed to be a static method decorated with @staticmethod, because you don't use the class instance (self).其次,即使您使用参数,它也应该是用@staticmethod 修饰的 static 方法,因为您不使用 class 实例(self)。

Therefore, I would go with a static method that utilizes the proper input variables it needs.因此,我会使用 go 和 static 方法,利用它需要的正确输入变量。 Something like:就像是:

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)

This is a good use case for @property decorator.这是@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

Also as my preference I would use @dataclass:另外作为我的偏好,我会使用@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

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

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