python-3.x mypy不能识别类的方法

6ojccjat  于 2023-03-24  发布在  Python
关注(0)|答案(2)|浏览(157)
from abc import ABC, abstractmethod
from typing import List

class AirConditioner:
    """Class that represents an air conditioner"""

    def __init__(self, identify: str, state: bool, temperature: int):
        self.identify = identify
        self._state = state
        self._temperature = temperature

    def turn_on(self) -> None:
        self._state = True

    def turn_off(self) -> None:
        self._state = False

    def set_temperature(self, temperature: int) -> None:
        self._temperature = temperature

    def get_state(self) -> bool:
        return self._state

    def get_temperature(self) -> int:
        return self._temperature

class ICommand(ABC):
    """Interface that represents a command"""

    @abstractmethod
    def execute(self) -> None:
        pass

    @abstractmethod
    def undo(self) -> None:
        pass

class TurnOnAirConditioner(ICommand):
    """Class that represents a command to turn on an air conditioner"""

    def __init__(self, air_conditioner: AirConditioner):
        self._air_conditioner = air_conditioner

    def execute(self) -> None:
        self._air_conditioner.turn_on()

    def undo(self) -> None:
        self._air_conditioner.turn_off()

class ChangeTemperatureAirConditioner(ICommand):
    """Class that represents a command to change the temperature of an air conditioner"""

    def __init__(self, air_conditioner: AirConditioner):
        self._air_conditioner = air_conditioner
        self._temperature = air_conditioner.get_temperature()
        self._temperature_anterior = self._temperature

    def set_temperature(self, temperature: int) -> None:
        self._temperature_anterior = self._temperature
        self._temperature = temperature

    def execute(self) -> None:
        self._air_conditioner.set_temperature(self._temperature)

    def undo(self) -> None:
        self._air_conditioner.set_temperature(self._temperature_anterior)

class Aplicativo:
    """Class that represents an application that uses the command pattern to control an air conditioner"""

    def __init__(self) -> None:
        self._comandos: List[ICommand] = []

    def set_comando(self, comando_app: ICommand) -> int:
        self._comandos.append(comando_app)
        return len(self._comandos) - 1

    def get_command(self, comando_id: int) -> ICommand:
        return self._comandos[comando_id]

    def pressing_button(self, comando_id: int) -> None:
        self._comandos[comando_id].execute()

if __name__ == "__main__":
    app = Aplicativo()

    my_air_conditioner = AirConditioner("Air Conditioner", False, 26)

    change_temperature_air = ChangeTemperatureAirConditioner(my_air_conditioner)
    turn_on_ar = TurnOnAirConditioner(my_air_conditioner)

    ID_TURN_AIR_ON = app.set_comando(turn_on_ar)
    ID_CHANGE_AIR_TEMPERATURE = app.set_comando(change_temperature_air)

    app.pressing_button(ID_TURN_AIR_ON)
    comando = app.get_command(ID_CHANGE_AIR_TEMPERATURE)
    comando.set_temperature(25)

当我运行上面的代码时,mypy给我带来了以下警报:
错误:“ICommand”没有属性“set_temperature”[attr-defined]
当我需要调用一个方法,但不是每个实现ICommand接口的类都有这个方法时,我该怎么做呢?
我尝试用#type ignore注解行,但我想知道处理这个问题的更好方法

oyt4ldly

oyt4ldly1#

请看下面两行:

comando = app.get_command(ID_CHANGE_AIR_TEMPERATURE)
comando.set_temperature(25)

即使我们忽略你调用变量ID_CHANGE_AIR_TEMPERATURE的事实,它仍然意味着你知道comandoChangeTemperatureAirConditioner类型,从你如何使用它(你在它上面调用.set_temperature(25))。
一个解决方案是从ICommandChangeTemperatureAirConditionercast

from typing import cast
comando = cast(ChangeTemperatureAirConditioner, app.get_command(ID_CHANGE_AIR_TEMPERATURE))
osh3o9ms

osh3o9ms2#

遵循mypy指南:
如果您的代码太过神奇,我无法理解,您可以通过显式地赋予变量或参数Any类型来使其动态类型化
来源:https://mypy.readthedocs.io/en/stable/dynamic_typing.html
解决这个问题的最好方法是将Aplicativo类中的get_command方法更改为:

from abc import ABC, abstractmethod
from typing import List, Any
    
    ...

class Aplicativo:
        """Class that represents an application that uses the command pattern to control an air conditioner"""
    
        ...

        def get_command(self, comando_id: int) -> Any:
            return self._comandos[comando_id]

        ...

解决我的问题

相关问题