在下面的代码中,我有两个类包含应该返回另一个实例的方法,并且没有注释可以按预期工作:
class Foo:
def __init__(self, bar = None):
self.bar = bar or Bar(self)
def foo(self):
return self.bar
class Bar:
def __init__(self, foo = None):
self.foo = foo or Foo(self)
def bar(self):
return self.foo
f = Foo() # verify everything works as intended
assert f.foo().bar() == f
但是,在代码中添加类型注释会导致NameError
任何注释都Foo
指示Bar
为类型,因为Bar
尚未声明:
from typing import *
class Foo:
def __init__(self, bar : Optional[Bar] = None):
self.bar = bar or Bar(self)
def foo(self) -> Bar:
return self.bar
class Bar:
def __init__(self, foo : Optional[Foo] = None):
self.foo = foo or Foo(self)
def bar(self) -> Foo:
return self.foo
在这种情况下,简单地切换顺序也无济于事,因为Bar
还需要Foo
在其注释中引用。
如何使用尚未声明的类注释函数?
在其他语言中,这将通过前向声明来处理,但是我不知道 python 中有这样的功能。我尝试了“明显”的方法来模拟前向声明(声明一个空类),虽然它表面上看起来有效,但实际上检查注释表明这种方法存在缺陷:
from typing import *
class Bar:
pass
class Foo:
def __init__(self, bar : Optional[Bar] = None):
self.bar = Bar(self) if bar is None else bar
def foo(self) -> Bar:
return self.bar
class Bar:
def __init__(self, foo : Optional[Foo] = None):
self.foo = Foo(self) if foo is None else foo
def bar(self) -> Foo:
return self.foo
assert get_type_hints(Bar.bar)['return'] == Foo #correct
# but the original `Bar` used in the annotation is different
# from the redeclared one so this fails:
assert get_type_hints(Foo.foo)['return'] == Bar
另一种可能性是Foo
使用 的基类进行注释Bar
,但这开始变得相当混乱:
from typing import *
from abc import ABCMeta, abstractmethod
class Bar_Base(object, metaclass=ABCMeta):
@abstractmethod
def __init__(self):
pass
class Foo:
def __init__(self, bar : Optional[Bar_Base] = None):
self.bar = Bar(self) if bar is None else bar
def foo(self) -> Bar_Base:
return self.bar
class Bar(Bar_Base):
def __init__(self, foo : Optional[Foo] = None):
super().__init__()
self.foo = Foo(self) if foo is None else foo
def bar(self) -> Foo:
return self.foo
assert issubclass(Foo, get_type_hints(Bar.bar)['return']) #correct
assert issubclass(Bar, get_type_hints(Foo.foo)['return']) #correct
如何使用尚未声明的类注释函数?