Если вы опустите подсказку типа для self
, средство проверки типов автоматически предположит, что он имеет любой тип содержащего класса.
Это означает, что:
class A:
def foo(self) -> None: pass
... эквивалентно выполнению:
class A:
def foo(self: A) -> None: pass
Если вы хотите, чтобы self
был чем-то другим, вы должны установить подсказку пользовательского типа.
Относительно этого фрагмента кода:
from typing import TypeVar
Self = TypeVar("Self")
class A:
def foo(self: Self) -> None:
pass
A.foo(1)
Использование TypeVar только один раз в сигнатуре функции либо искажено, либо избыточно, в зависимости от вашей точки зрения.
Но это не имеет отношения к основная направленность вашего вопроса. Мы можем исправить ваш фрагмент кода, вместо этого выполнив:
from typing import TypeVar
Self = TypeVar("Self")
class A:
def foo(self: Self) -> Self:
return self
A.foo(1)
... который демонстрирует то же поведение, которое вы заметили.
Но независимо от того, на какой из двух фрагментов кода мы смотрим, я полагаем, что средство проверки типов действительно предположит, что self
имеет тот же тип, что и верхняя граница Self
, при проверке типа тела foo
. В этом случае верхняя граница object
, как вы и подозревали.
Мы получаем такое поведение вне зависимости от того, делаем мы что-нибудь с собой или нет. Например, мы бы получили точно такое же поведение, просто выполнив:
def foo(x: Self) -> Self:
return x
... и так далее. С точки зрения средства проверки типов в параметре self
нет ничего особенного, за исключением того, что мы устанавливаем для него тип по умолчанию, если ему не хватает подсказки типа, вместо того, чтобы просто использовать Any
.
ошибка: «Self» не имеет атрибута «bar»
, который я могу исправить, если привязать как Self = TypeVar("Self", bound='A')
Я прав, что это означает, что self
является не ограничен, например, так же, как я ожидал бы, что this
будет ограничен в Scala?
Я не знаю, как this
ограничен в Scala, но это действительно, если вы решили переопределить тип по умолчанию self
, вы несете ответственность за установку своих собственных ограничений и границ в зависимости от ситуации.
Другими словами, как только TypeVar определен, его значение не изменится, когда вы попытаетесь использовать его в определении функции. Это правило для TypeVars / функций в целом. И поскольку в основном self
нет ничего особенного, то же правило применяется и там.
(Хотя средства проверки типов, такие как mypy, также попытаются выполнить некоторые базовые c проверки работоспособности любых ограничений, которые вы в конечном итоге выберете убедитесь, что вы не получите метод, который невозможно вызвать или что-то еще. Например, он пожалуется, если вы попытаетесь установить границу от Self
до int
.)
Обратите внимание, что выполнение таких действий, как:
from typing import TypeVar, List
Self = TypeVar('Self', bound='A')
class A:
def foo(self: Self, bar: List[Self]) -> Self:
...
class B(A): pass
x = A().foo([A(), A()])
y = B().foo([B(), B()])
reveal_type(x) # Revealed type is 'A'
reveal_type(y) # Revealed type is 'B'
..., явно поддерживается PEP 484 . В документации mypy также есть несколько примеров .