Я пишу библиотеку, которая предоставляет класс, который должен быть разделен на подклассы конечными пользователями. Конструктор класса заботится о типах аргументов методов, добавляемых в подкласс. Я хочу, чтобы конечные пользователи могли указывать типы аргументов с помощью аннотаций типов.
Одна из вещей, о которой заботится мой класс, - является ли аргумент строкой, содержащей путь к файлу. По логике это должен быть подтип str
, который можно обозначить так:
import mylib
from typing import *
FilePath = NewType('FilePath', AnyStr)
class MySubclass(mylib.MyClass):
def my_method(self, path: FilePath):
return open(path)
Но строка документа typing.NewType
дает следующие примеры:
from typing import *
UserId = NewType('UserId', int)
def name_by_id(user_id: UserId) -> str:
...
name_by_id(42) # Fails type check
name_by_id(UserId(42)) # OK
Таким образом, чтобы статическая проверка типов не вызывала сбоев кода, использующего мою библиотеку, пользователям необходимо было сделать следующее:
from mylib import *
... # MySubclass defined as above
o = MySubclass()
o.my_method(FilePath('foo/bar.baz'))
Но я хочу, чтобы они могли просто сделать
o.my_method('foo/bar.baz')
без статической ошибки проверки типов. Это связано с тем, что меня беспокоит семантика определяемых мной типов, а не опасность того, что кто-нибудь когда-либо реально использует мой код и , пытаясь запустить на нем статическую проверку типов.
Одним из решений является определение FilePath
как
FilePath = Union[AnyStr, NewType('FilePath', AnyStr)]
но это сбивает с толку взгляд, и его __repr__
- откровенная ложь:
>>> FilePath
Union[Anystr, FilePath]
Есть ли лучший способ?