【问题标题】:Calling @classmethod decorated method throws a TypeError调用 @classmethod 修饰方法会引发 TypeError
【发布时间】:2017-04-17 09:10:29
【问题描述】:

我正在尝试找出@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'

这是课程,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

【问题讨论】:

  • 您尝试做的事情毫无意义。 cls.temperature 指的是描述符对象本身,而不是具有值的实例。类方法和静态方法都不能访问任何实例值。
  • 为什么要to_cto_f 成为类方法?他们可能想要转换的温度(如果您不更改他们的定义以给他们一个参数)是_temperature 实例属性,因为该名称的类属性将始终为0。确实不需要 class 属性,即使作为默认值,因为每个实例都会获得构造函数(通过属性)分配的值。

标签: python static-methods read-eval-print-loop class-method


【解决方案1】:

问题:您试图从类中访问 temperature 属性并期望与实例相同的结果,在本例中,int 的值为 41。但是,属性在实例和类中的调用方式不同。比较每个__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>

这里有更多关于__get__ 方法签名的information 和关于描述符如何工作的SO post。在这种情况下,签名可以被视为C.__get__(self, inst, cls)。简而言之,当从属性中获取时,与实例调用不同,来自类的调用将 None 传递给实例参数

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

C.temperature
# <property at 0x4ab9458>

我们还能从属性对象中“获取”值吗?让我们在属性对象上调用__get__

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

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

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

【讨论】:

  • 啊,出于某种原因,我认为类对象的instance 正在通过cls 传递给to_c(cls)。我错了...谢谢@pylang 的启发
猜你喜欢
  • 2016-03-17
  • 2010-09-28
  • 1970-01-01
  • 2012-10-30
  • 2016-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多