【问题标题】:Is it possible to call getter and setter properties with parameters in Python?是否可以在 Python 中使用参数调用 getter 和 setter 属性?
【发布时间】:2021-01-11 22:52:32
【问题描述】:

这可能无法按照我想要的方式完成。我在 python 中制作了class Temperature

我想设置一个名为 temperature 的属性,并在不同的尺度(例如凯文、摄氏或华氏)上设置或检索其值。

设定温度:

T = Temperature() 
T.temperature = 20                # Set temperature to 20ºC
T.temperature('Fahrenheit') = 68  # Set temperature to 68ºF
T.temperature('Kelvin') = 305     # Set temperature to 305K

获取温度:

t = T.temperature                 # retrieves temperature in Celsius
t = T.temperature('Fahrenheit')   # retrieves temperature in Fahrenheit
t = T.temperature('Kelvin')       # retrieves temperature in Kelvin

我有这个代码。首先,我尝试使用 @property 装饰器,但它不起作用。然后我决定改用传统语法,使用x=property(x_get, x_set)

class Temperature:
    def __init__(self, temperature:float = 0, scale:str = "Celsius"):
        # All temperatures will be stored as KELVIN
        self._temperature = None
        self.set_temperature(temperature, scale)

    def get_temperature(self, scale: str = "Celsius"):
        converter = {
            "Celsius": self._temperature - 273.15,
            "Fahrenheit": ((self._temperature - 273.15) * 1.8) + 32,
            "Kelvin": self._temperature
        }
        value = converter.get(scale)

        return value

    def set_temperature(self, value: float, scale: str = "Celsius"):
        converter = {
            "Celsius": value + 273.15,
            "Fahrenheit": (value - 32) / 1.8 + 273.15,
            "Kelvin": value
        }

        self._temperature = converter.get(scale)

        if self._temperature < 0 :
            self._temperature = None
            raise ValueError("Temperature below 0 Kelvin is not possible")

    temperature = property(get_temperature, set_temperature)

但我不能使用建议的语法;虽然使用传统语法似乎是一个不错的方法。

在不带任何参数调用属性temperature或直接获取和设置带参数的方法时有效:

>>> T = Temperature(20) # Initialize
>>> T.temperature       # Getter
20.0

>>> T.temperature=30    # Setter
>>> T.temperature       # Getter
30.0

如果我直接打电话给get_temperatureset_temperature 就可以了

>>> T.get_temperature("Fahrenheit")
86.0

但是,如果我使用参数调用 getter 或 setter 属性,则会引发错误:

T.temperature("Fahrenheit")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'float' object is not callable

或者

T.temperature("Kelvin") = 301.15
  File "<input>", line 1
SyntaxError: can't assign to function call


T.temperature = 68, 'Fahrenheit'
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 19, in set_temperature
TypeError: can only concatenate tuple (not "float") to tuple

【问题讨论】:

    标签: python properties getter-setter


    【解决方案1】:

    我不认为 getter 和 setter 是必需的,pythonic 也不是...通过使用 getter 和 setter,您可以将类的属性设为私有以保护它们免受其他代码的影响。提供这种保护的 Python 方式实际上是通过公开引入属性。

    要以伪 java 的方式设计一个类,您可以执行以下操作:

    class temperature:
    
        def __init__(self.temp):
            self.__temp = temp
        
        def get_temp(self): 
            return self.__temp
       
        def set_temp(self, temp):
            self.__temp = temp
    
    

    要访问数据,您需要执行以下操作

    >>>temp1 = temperature(135)
    >>>temp1.set_temp(14)
    >>>temp1.get_temp()
    14
    

    然而,设计这个类的更 Pythonic 的方式是不使用 getter 和 setter 并使用公共属性。

    class temperature: 
    
        def __init__(self, temp): 
            self.temp = temp
    

    现在您无需使用 getter 或 setter 即可访问相同的属性

    >>>temp1 = temperature(14)
    >>>temp1.temp
    14
    

    尽管数据不一定以这种方式封装……但实际上并不需要。

    我意识到这并不能解决您对三个温标的担忧,但这可以通过将输入温度指定为某个单位然后使用转换等轻松解决......

    编辑

    来自@Carlo 的评论

    pythonic 温度类可以在下面完成,假设您指定输入温度单位为开尔文,否则该类需要扩展以包括华氏温度和摄氏度输入温度

    class temperature():
    
        def __init__(self, temp, unit):
            self.temp = temp
            self.unit = unit
    
            if self.unit == 'K':
                self.temp_k = self.temp
                self.temp_c = self.temp_k + 273
                self.temp_f = (self.temp_k + 273)*(9/5)+32
            else:
                raise TypeError("only kelvin accepted as input temperature")
    
    
    if __name__ == '__main__':
    
        temp1 = temperature(14, 'K')
        temp2 = temperature(14, 'C')  # will raise error
    
    

    访问 temp1 对象的温度值就变成了

    >>> temp1.temp_k
    14
    >>> temp1.temp_c
    287
    >>> temp1.temp_f
    548.6
    

    【讨论】:

    • 不错!我给你一个改进它的提示,也许你可以创建两个单独的 setter/getter,一个带有温度,另一个带有转换类型。您必须管理类型转换的初始化并使用它。
    • 我想实现不同的温标。以及在单行代码中设置或检索它的简单方法。最好使用属性,尽管我想我最终会使用方法
    • 上述类只使用init方法建立转换后的值,没有额外的转换方法。您可以根据初始温度输入“获取”不同温度单位的值,如果您想使用不同的输入温度值,只需将这些条件包含在一组额外的 if 语句中。
    • 感谢您的回答和 cmets。我将使用属性“温度”和两种方法“get_temperature”和“set_temperature”来处理那些不适用于默认比例的值。
    猜你喜欢
    • 1970-01-01
    • 2021-12-02
    • 2011-08-25
    • 2021-06-19
    • 1970-01-01
    • 1970-01-01
    • 2012-10-02
    • 1970-01-01
    相关资源
    最近更新 更多