英文:
mypy does not recognize a method of a class
问题
The error you're encountering is because the "ICommand" interface doesn't define a "set_temperature" method, but your "ChangeTemperatureAirConditioner" class, which implements "ICommand," has a "set_temperature" method. You can handle this situation by making the "set_temperature" method optional in the interface using Python's Optional
from the typing
module.
Here's the modified code for "ICommand" and "ChangeTemperatureAirConditioner":
from abc import ABC, abstractmethod
from typing import List, Optional
class ICommand(ABC):
"""Interface that represents a command"""
@abstractmethod
def execute(self) -> None:
pass
@abstractmethod
def undo(self) -> None:
pass
@abstractmethod
def set_temperature(self, temperature: int) -> None:
pass
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)
By adding set_temperature
to the ICommand
interface, you avoid the error, and you can implement the method in classes where it's needed and leave it unimplemented in classes where it's not applicable.
英文:
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)
When I run the code above, mypy brings me the following alert:
error: "ICommand" has no attribute "set_temperature" [attr-defined]
How do I do it when I need to call a method, but not every class that implements the ICommand interface has this method?
I tried to comment lines with #type ignore, but I would like to know a better way to handle this problem
答案1
得分: 1
考虑以下两行:
comando = app.get_command(ID_CHANGE_AIR_TEMPERATURE)
comando.set_temperature(25)
即使我们忽略您将变量命名为`ID_CHANGE_AIR_TEMPERATURE`的事实,从您的使用方式来看,它仍意味着您知道`comando`的类型是`ChangeTemperatureAirConditioner`(您在其上调用`.set_temperature(25)`)。
一种解决方法是从`ICommand`转换为`ChangeTemperatureAirConditioner`:
from typing import cast
comando = cast(ChangeTemperatureAirConditioner, app.get_command(ID_CHANGE_AIR_TEMPERATURE))
英文:
Consider these two lines:
comando = app.get_command(ID_CHANGE_AIR_TEMPERATURE)
comando.set_temperature(25)
Even if we ignore the fact that you call your variable ID_CHANGE_AIR_TEMPERATURE
, it still implies that you know comando
is of type ChangeTemperatureAirConditioner
from how you use it (you call .set_temperature(25)
on it).
One solution would then be to cast
from ICommand
to ChangeTemperatureAirConditioner
:
from typing import cast
comando = cast(ChangeTemperatureAirConditioner, app.get_command(ID_CHANGE_AIR_TEMPERATURE))
答案2
得分: 0
Sure, here's the translated content:
遵循 mypy 指南:
> 在您的代码对于 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:
"""代表一个使用命令模式来控制空调的应用程序的类"""
...
def get_command(self, comando_id: int) -> Any:
return self._comandos[comando_id]
...
解决了 mypy 的问题。
英文:
Following mypy guidelines:
> In cases where your code is too magical for mypy to understand, you
> can make a variable or parameter dynamically typed by explicitly
> giving it the type Any
source: https://mypy.readthedocs.io/en/stable/dynamic_typing.html
The best way to solve this problem is change get_command
method, in Aplicativo
class to:
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]
...
Solving the issue with mypy
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论