我希望将方法参数约束为与调用它的类相同的类型(请参阅末尾的示例)。 当我试图这样做的时候,我遇到了这样的行为,我很难让自己的头脑清醒过来。
以下内容不键入检查
class A:
def foo(self) -> None:
pass
A.foo(1)
与
错误:“A”的“foo”的参数1具有不兼容的类型“int”; 应为“A”
正如我所预料的,因为我认为a.foo
应该只接受一个a
。 但是,如果我添加了self类型
from typing import TypeVar
Self = TypeVar("Self")
class A:
def foo(self: Self) -> None:
pass
A.foo(1)
它进行类型检查。 我本以为它会失败,告诉我需要传递一个a
,而不是一个int
。 这表明类型检查器为self
推断类型a
,添加一个self
类型将覆盖该类型,我猜是为object
。 这符合错误
from typing import TypeVar
Self = TypeVar("Self")
class A:
def bar(self) -> int:
return 0
def foo(self: Self) -> None:
self.bar()
错误:“self”没有属性“bar”
如果绑定为self=TypeVar(“self”,bound='a')
,则可以修复
这意味着self
没有受到约束,例如,我期望this
在Scala中受到约束的方式是对的吗?
我猜只有当我有意或无意地将self
的类型指定为它所定义的类以外的任何类型时,这才会有影响。 我还很想知道将self
重写为另一种类型会有什么影响,以及它对Python解析和调用方法的方式是否有意义。
上下文
我想做一些像这样的事情
class A:
def foo(self: Self, bar: List[Self]) -> Self:
...
但我原以为self
会被限制为a
,但很惊讶,事实并非如此。
两件事:
self
参数有一个神奇的特性,即如果您将对象的属性作为函数调用,而该函数将self
作为其第一个参数,则对象本身将作为self
附加到显式参数之前。
我猜任何一个好的静态分析器都会认为self
将有问题的类作为其类型是隐含的,这就是您在第一个示例中看到的。
我想这就是你想做的? 在第三个示例中,self
可以是任何类型,具体取决于上下文。 在a.foo(1)
上下文中,self
是int
,因此self.bar()
失败。
可以编写一个实例方法,该方法可以作为静态方法针对具有参数类型限制的类非成员进行调用,但对于任何野外应用程序来说,这可能都不是一个好主意。 只需将变量命名为其他内容,并将方法声明为静态的。
它失败的原因是为了能够使用self
,您必须具有__init_
函数。 这将创建该类的实例,并允许您使用self
。 如果没有__init_
,则该类只能调用函数或返回变量。