Подсказка типа против утиного набора - PullRequest
2 голосов
/ 04 августа 2020

Одним из минусов использования подсказки типов в Python является торговля красотой кода Python.

До подсказки типов мои сигнатуры методов были краткими:

def echo(items):
    for i in items:
        print(i)
    

Поскольку мои команда использует подсказки типов, я также добавил подсказки типов в свой код:

def echo(items: Set[str]) -> None:

Все еще довольно разборчиво. Через некоторое время другие части моего кода, работающие с набором наборов, потребовали, чтобы мой items был хешируемым, а другие - нет. Поэтому я решил также поддерживать frozenset, и теперь мой метод выглядит так:

 def echo(items: Union[Set[str],Frozenset[str]]) -> None:
 

Он начал выглядеть как методы в Java, хотя в Java я мог работать с интерфейсами, игнорируя реализацию. подробности:

 void echo(Set<String> items) {

Python не поддерживает концепцию интерфейса, т.е. я не могу утверждать, что Set реализует Frozenset. Первоначальная реализация будет работать как для Set, так и для Frozenset благодаря утиной печати: оба ведут себя как установлено. Однако у меня сложилось впечатление, что явное указание типа почему-то не очень хорошо сочетается с уткой

Как мне найти хороший баланс между подсказкой и уткой?

Ответы [ 2 ]

5 голосов
/ 04 августа 2020

Используйте AbstractSet:

from typing import AbstractSet

def echo(items: AbstractSet[str]) -> None:
    ...

Оба Set и FrozenSet наследуют (прямо или косвенно) от AbstractSet:

AbstractSet
    |
    |
    +--------------+
    |              |
    |              |
MutableSet        FrozenSet
    |
    |
   Set
2 голосов
/ 04 августа 2020

Как сказал @chpner, это хороший вариант для использования встроенных типов. Все абстрактные типы из модуля набора текста - это протоколы , начиная с Python 3.7.

Концепция протоколов имеет некоторое сходство с интерфейсами.

Как сказано в документации:

Структурное подтипирование можно рассматривать как статический c эквивалент утиного набора, который хорошо известен программистам Python. Mypy обеспечивает поддержку структурных подтипов через классы протокола, описанные ниже. См. PEP 544 для получения подробной спецификации протоколов и структурных подтипов в Python.

Также можно определить собственные протоколы:

from typing import Iterable
from typing_extensions import Protocol

class SupportsClose(Protocol):
    def close(self) -> None:
       ...  # Empty method body (explicit '...')

class Resource:  # No SupportsClose base class!
    # ... some methods ...

    def close(self) -> None:
       self.resource.release()

def close_all(items: Iterable[SupportsClose]) -> None:
    for item in items:
        item.close()

close_all([Resource(), open('some/file')])  # Okay!

Пока Основное назначение протоколов - анализ статистики c, они позволяют проверить, следует ли объект какому-либо протоколу во время выполнения:

from typing_extensions import Protocol, runtime_checkable

@runtime_checkable
class Portable(Protocol):
    handles: int

class Mug:
    def __init__(self) -> None:
        self.handles = 1

mug = Mug()
if isinstance(mug, Portable):
   use(mug.handles)  # Works statically and at runtime
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...