Сегодня я обнаружил эту ошибку в нашей кодовой базе (упрощенный пример):
from abc import ABC, abstractmethod
class Interface(ABC):
@abstractmethod
def method(self, variable: str) -> str:
pass
class Implementation(Interface):
def method(self, variable_changed: str) -> str:
return "A"
Implementation().method("d") # works
Implementation().method(variable = "d") # error
Implementation().method(variable_changed = "d") # works
Здесь у нас есть класс, реализующий интерфейс. Это все хорошо, но реализация меняет имя первого аргумента метода. Если я запущу mypy, я ожидаю получить ошибку, потому что реализация не соответствует контракту, определенному интерфейсом. К моему удивлению, это совсем не так.
Я не уверен, задумано это или нет, но я хотел бы обнаруживать такие несоответствия как можно скорее. Любая идея, как исправить mypy или как включить такое обнаружение, если это не ошибка?
Мм, если это заставляет mypy выдавать ошибку, тогда реализация не соответствует интерфейсу, тогда да, всегда с именем.
Поместите *
в список параметров сразу после self
, чтобы указать, что все остальные параметры являются именованными, а не позиционными. См.: docs.python.org/3/reference/… и stackoverflow.com/questions/14301967/…
Ммм, но тогда мне нужно добавить это во все мои интерфейсы. И мне нужно было бы помнить об этом каждый раз, когда я добавляю новый интерфейс. Вместо этого я бы предпочел, чтобы mypy не работал.
о, так что я полагаю, что тогда это еще невозможно :(. У меня возникает соблазн изучить достаточно mypy внутренностей и сделать пиар, лол, хахаха. Не могли бы вы написать свои мысли в ответе, чтобы пометить его как принятый? :)
Mypy рассматривает параметры как позиционные, если они явно не указаны как именованные. Таким образом, ваш Interface
требует, чтобы method
принимал только один аргумент, а не чтобы у него было конкретное имя.
Чтобы указать его как именованный параметр (заставляя реализации соответствовать имени), вы должны сделать:
def method(self, *, variable: str) -> str:
чтобы сказать, что variable
является именованным параметром (и всегда должен вызываться как таковой).
Обсуждение изменения этого поведения в mypy см. в соответствующей проблеме GitHub: https://github.com/python/mypy/issues/6709
«Официальные» имена — это параметры позиции или ключа (для традиционного параметра, который может быть установлен с использованием позиционных или ключевых аргументов) и параметры только с ключевым словом (для тех, которые могут быть установлены только с помощью аргументов ключевого слова). См. docs.python.org/3/glossary.html#term-parameter.
Mypy по умолчанию обрабатывает аргументы как позиционные, что означает, что имя не имеет значения. Вы хотите, чтобы этот аргумент всегда назывался?