Передача списка здесь принципиально небезопасна для типов. Например, что если вы это сделаете?
def func(objects: List[Parent]) -> None:
print(objects)
objects.append(Parent())
children: List[Child] = [Child(), Child(), Child()]
func(children)
# Uh-oh! 'children' contains a Parent()!
Если бы это было разрешено для проверки типа, ваш код в конечном итоге содержал бы ошибку.
Чтобы использовать жаргон типов, List
намеренно разработан как инвариантный тип. То есть, хотя Child
является подклассом Parent
, это не тот случай, когда List[Child]
является подтипом List[Parent]
, или наоборот. Дополнительную информацию об инвариантности можно найти здесь и здесь.
Самая распространенная альтернатива - использовать вместо этого Sequence
, который является интерфейсом / протоколом только для чтения / чем угодно. А поскольку Sequence доступен только для чтения, он может быть ковариантным безопасно: то есть Sequence[Child]
считается допустимым подтипом Sequence[Parent]
.
В зависимости от того, что именно вы делаете, вы можете использовать введите переменные. Например. вместо того, чтобы сказать «эта функция принимает список Parent», вы говорите «эта функция принимает список любого класса, который является Parent, или подклассом Parent»:
TParent = TypeVar('TParent', bound=Parent)
def func(objects: List[TParent]) -> List[TParent]:
print(objects)
# Would not typecheck: we can't assume 'objects' will be a List[Parent]
objects.append(Parent())
return objects
В зависимости от того, что именно вы делаете, вы можете создать собственный протокол, который определяет коллекцию, подобную списку только для записи (или настраиваемую структуру данных). А поскольку ваша структура данных будет доступна только для записи, вы можете сделать ее контравариантной, то есть WriteOnlyThing[Parent]
будет подтипом WriteOnlyThing[Child]
. Затем вы заставляете func
принимать WriteOnlyThing[Child]
и можете безопасно передавать как WriteOnlyThing[Child]
, так и WriteOnlyThing[Parent]
.
Если ни один из подходов не работает в вашем случае, ваш единственный выход - либо использовать # type: ignore
, чтобы заглушить ошибку (не рекомендуется), отказаться от проверки типов содержимого списка и сделать аргумент типа List[Any]
(также не рекомендуется), либо выяснить, как реструктурировать код, чтобы он был безопасным по типам.
person
Michael0x2a
schedule
13.11.2018