调用@classmethod 修饰的方法会抛出 TypeError
Calling @classmethod decorated method throws a TypeError
我想找出 @staticmethod
和 @classmethod
之间的区别。后者传递了一个 cls
实例。
当我试图调用 @classmethod
时,它给我一个错误。
我应该如何在 REPL 中调用 @classmethod
(to_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
。
我想找出 @staticmethod
和 @classmethod
之间的区别。后者传递了一个 cls
实例。
当我试图调用 @classmethod
时,它给我一个错误。
我应该如何在 REPL 中调用 @classmethod
(to_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
。