调用@classmethod 修饰的方法会抛出 TypeError

Calling @classmethod decorated method throws a TypeError

我想找出 @staticmethod@classmethod 之间的区别。后者传递了一个 cls 实例。

当我试图调用 @classmethod 时,它给我一个错误。

我应该如何在 REPL 中调用 @classmethodto_c()to_f())装饰方法?

这里是 REPL 调用

>>> from temperature_converter import *
>>> c = TemperatureConverter(41)
>>> TemperatureConverter.to_f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Repos\Python\module-3\temperature_converter.py", line 21, in to_f
    return cls.c_to_f(cls.temperature)
  File "C:\Repos\Python\module-3\temperature_converter.py", line 25, in c_to_f
    return celsius * 9 / 5 + 32
TypeError: unsupported operand type(s) for *: 'property' and 'int'

这里是class,TemperatureConverter

class TemperatureConverter:
    _temperature = 0

    @property
    def temperature(self):
        return self._temperature

    @temperature.setter
    def temperature(self, value):
        self._temperature = value

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

    @classmethod
    def to_c(cls):
        return cls.f_to_c(cls.temperature)

    @classmethod
    def to_f(cls):
        return cls.c_to_f(cls.temperature)

    @staticmethod
    def c_to_f(celsius):
        return celsius * 9 / 5 + 32

    @staticmethod
    def f_to_c(fahrenheit):
        return (fahrenheit - 32) * 5/9

问题:您试图从 class 访问 temperature 属性 并期望与实例相同的结果,在此假设 int 值为 41。但是,属性在实例和 classes 中的调用方式不同。比较每个的 __get__ 方法:

描述

# Reassignments for illustration
C = TemperatureConverter                                   # class  
i = c                                                      # instance 
attr = "temperature"                                       # attribute    

# Call via Instance binding, `c.temperature`
C.__dict__[attr].__get__(i, C)                     
# 41

# Call via Class binding, `C.temperature`
C.__dict__[attr].__get__(None, C)                      
# <property at 0x4ab9458>

这里有更多关于描述符如何工作的information on the signature of the __get__ method and a SO post。在这种情况下,签名可以看作是 C.__get__(self, inst, cls)。简而言之,当从 属性 获取时, 与实例调用不同,来自 class 的调用通过 None 获取实例参数 .

如上所示,如果绑定到 class,则返回 属性 对象:

C.temperature
# <property at 0x4ab9458>

我们还能 "get" 来自 属性 对象的值吗?让我们在 属性 对象上调用 __get__

C.temperature.__get__(i, C)
# 41

后者表明在绑定到 class 时可以获得 属性 值。虽然在 class 方法中对 cls.temperature 实施 __get__ 方法可能很诱人,但 您仍然需要传入一个实例 (例如 i) 访问 属性 的值。 class 方法中无法访问实例。因此,我们看到了为什么 属性 对象在您的代码中返回,它试图与 int 相乘并引发您观察到的错误。

这是对您的问题的一种解释,特别是描述了为什么您无法在 class 方法中访问 属性 值 cls.temperature