Как программист, долгое время использующий Unity для разработки игр, я использую язык программирования C #. Как вы знаете, C # - это строго типизированный язык, который обычно программируется с использованием объектно-ориентированной парадигмы (конечно, у нее есть и другие парадигмы). Недавно я начал использовать Python для программирования. Прошло 5–6 лет с тех пор, как я в последний раз использовал Python, а в то время я использовал Python 2.7. Поэтому у меня сложилось впечатление, что Python - это процессно-ориентированный язык динамического программирования без типов.
Конечно, теперь я знаю, что ошибаюсь. И я обнаружил, что следующие практики могут помочь таким программистам, как я, использующим C #, также привыкнуть к использованию Python.
Аннотация типа и комментарии к типу
Моей первой попыткой было сделать Python строго типизированным языком, по крайней мере, чтобы он выглядел как строго типизированный язык. Хорошая новость заключается в том, что начиная с Python3.5, Python представил аннотацию типов через PEP 484.
Например, вот простая функция, аргумент и тип возвращаемого значения которой объявлены в аннотациях:
def greeting(name: str) -> str: return 'Hello ' + name
Как вы можете видеть в приведенном выше примере, аннотация типа выполняется добавлением : <type>
после переменной. Кстати, если функция не вернет, тип возврата должен быть None
.
def retry(url: Url, retry_count: int) -> None: ...
Но что, если тип более сложный? Например, тип - это список, элементами которого являются int.
Для этой цели можно использовать модуль typing, начиная с Python 3.5. Этот модуль обеспечивает во время выполнения поддержку подсказок типов, как указано в PEP 484, PEP 526, PEP 544, PEP 586 , PEP 589 и PEP 591 . Наиболее фундаментальная поддержка состоит из типов Any
, Union
, Tuple
, Callable
, TypeVar
и Generic
.
С помощью набора текста вы можете добавить аннотацию типа следующим образом:
from typing import List def scale(scalar: float, vector: List[float]) -> List[float]: return [scalar * num for num in vector]
Однако в PEP 484 основное внимание уделялось аннотациям функций, синтаксис для ввода переменных был добавлен в Python 3.6 через PEP 526. Существует два варианта синтаксиса, с выражением инициализатора или без него:
from typing import Optional foo: Optional[int] # No initializer bar: List[str] = [] # Initializer
Другой способ добавить подсказку типа - это комментарий типа, синтаксис аннотации на основе комментариев для кода Python 2. Вот несколько примеров:
x = 1 # type: int x = 1.0 # type: float x = True # type: bool x = "test" # type: str x = u"test" # type: unicode
Комментарий типа достигается добавлением # type:
после переменной.
Интерфейс / абстрактный класс
Модуль стандартной библиотеки Python abc
(A bstract B ase C lass) часто используется для определения и проверки интерфейсов. Он определяет метакласс ABCMeta
и декораторы @abstractmethod
и @abstractproperty
.
from abc import ABCMeta, abstractmethod class AbstractStrategy(metaclass=ABCMeta): @abstractmethod def algorithm_interface(self): pass class ConcreteStrategyA(AbstractStrategy): def algorithm_interface(self): print("ConcreteStrategyA")
И еще одна альтернатива - использовать библиотеку interface. Это библиотека для объявления интерфейсов и статического подтверждения того, что классы реализуют эти интерфейсы.
from interface import implements, Interface class MyInterface(Interface): def method1(self, x): pass def method2(self, x, y): pass class MyClass(implements(MyInterface)): def method1(self, x): return x * 2 def method2(self, x, y): return x + y
Статические методы
Вы можете использовать декоратор @staticmethod
для определения статической функции в классе. Статический метод не получает неявный первый аргумент (self). И вот пример:
class C: @staticmethod def f(arg1, arg2, ...): ...
Теперь статический метод f()
можно вызывать либо в классе (например, C.f()
), либо в экземпляре (например, C().f()
).
Дженерики
Используя упомянутый выше модуль typing, вы можете использовать универсальные шаблоны в Python. Модуль набора текста предоставляет несколько общих коллекций, таких как List, Mapping, Dict. Это общая версия list, Mapping, dict соответственно.
T = TypeVar('T', int, float) def vec2(x: T, y: T) -> List[T]: return [x, y] def keep_positives(vector: Sequence[T]) -> List[T]: return [item for item in vector if item > 0] def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: return word_list[word] def count_words(text: str) -> Dict[str, int]: ...
Пользовательский класс также может быть определен как общий класс. Классу нужно только наследовать Generic
. Generic - абстрактный базовый класс для универсальных типов. Например, общий определяемый пользователем класс может быть определен как:
from typing import TypeVar, Generic from logging import Logger T = TypeVar('T') class LoggedVar(Generic[T]): def __init__(self, value: T, name: str, logger: Logger) -> None: self.name = name self.logger = logger self.value = value
Класс LoggedVar
принимает параметр единственного типа T
.
Затем класс LoggedVar
можно использовать следующим образом:
T = TypeVar('T') def foo(logged: LoggedVar[T]) -> None:
Что ж, благодаря вышеуказанным методам программирования я, программист на C #, могу использовать знакомый способ программирования с использованием языка Python. Да!
Спасибо, что прочитали, надеюсь, статья была вам полезна!