vel*_*lis 65 python type-hinting pycharm python-3.4 python-3.5
我想把我的大班分成两部分; 好吧,基本上进入"主"类和具有附加功能的mixin,如下所示:
import mymixin.py
class Main(object, MyMixin):
def func1(self, xxx):
...
Run Code Online (Sandbox Code Playgroud)
现在,虽然这很好用,但MyMixin.func2中的类型提示当然无法正常工作.我无法导入main.py,因为我得到一个循环导入而没有提示,我的编辑器(PyCharm)无法分辨出什么main.py是.
使用Python 3.4,如果有可用的解决方案,愿意转向3.5.
有没有什么办法可以将我的课分成两个文件并保留所有的"连接",以便我的IDE仍然提供自动完成功能以及知道类型的所有其他好东西?
Mic*_*x2a 104
一般来说,没有一种非常优雅的方式来处理进口周期,我担心.您的选择是重新设计代码以消除循环依赖,或者如果不可行,请执行以下操作:
# some_file.py
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from main import Main
class MyObject(object):
def func2(self, some_param: 'Main'):
...
Run Code Online (Sandbox Code Playgroud)
该TYPE_CHECKING常数是始终False在运行,所以进口不会进行评估,但mypy(和其他类型检查工具)将评估该块的内容.
我们还需要将Main类型注释转换为字符串,有效地转发声明它,因为Main符号在运行时不可用.
如果您使用的是Python 3.7+,我们至少可以通过利用PEP 563来跳过必须提供明确的字符串注释:
# some_file.py
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from main import Main
class MyObject(object):
# Hooray, cleaner annotations!
def func2(self, some_param: Main):
...
Run Code Online (Sandbox Code Playgroud)
该from __future__ import annotations进口将使所有类型提示弦而跳过评估他们.这有助于使我们的代码更温和地符合人体工程学.
所有这一切,使用mixins和mypy可能需要比现在更多的结构.Mypy 推荐一种基本上deceze就是描述的方法 - 创建一个你的Main和MyMixin类都继承的ABC .如果您最终需要做类似的事情以使Pycharm的检查员满意,我不会感到惊讶.
Ben*_*res 22
从 Python 3.5 开始,将类分成单独的文件很容易。
\n实际上可以使用块内的import语句将方法导入到类中。例如,class ClassName:
class_def.py:
class C:\n from _methods1 import a\n from _methods2 import b\n\n def x(self):\n return self.a() + " " + self.b()\nRun Code Online (Sandbox Code Playgroud)\n在我的例子中,
\nC.a()将是一个返回字符串的方法helloC.b()将是一个返回的方法hello goodbyeC.x()将因此返回hello hello goodbye。要实施a和b,请执行以下操作:
_methods1.py:
from __future__ import annotations\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n from class_def import C\n\ndef a(self: C):\n return "hello"\nRun Code Online (Sandbox Code Playgroud)\n解释:TYPE_CHECKING是True当类型检查器正在读取代码时。由于类型检查器不需要执行代码,因此当循环导入发生在if TYPE_CHECKING:块内时就可以了。导入__future__启用延迟注释。这是可选的;如果没有它,您必须引用类型注释(即def a(self: "C"):)。
我们_methods2.py同样定义:
from __future__ import annotations\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n from class_def import C\n\ndef b(self: C):\n return self.a() + " goodbye"\nRun Code Online (Sandbox Code Playgroud)\nself.a()在 VS Code 中,我可以看到悬停时检测到的类型:\n
一切都按预期运行:
\n>>> from class_def import C\n>>> c = C()\n>>> c.x()\n\'hello hello goodbye\'\nRun Code Online (Sandbox Code Playgroud)\n对于 Python 版本 \xe2\x89\xa43.4,TYPE_CHECKING未定义,因此此解决方案不起作用。
对于 Python 版本 \xe2\x89\xa43.6,未定义推迟注释。作为解决方法,请省略from __future__ import annotations并引用上面提到的类型声明。
Sim*_*Art 21
与其强迫自己参与typing.TYPE_CHECKING恶作剧,有一种简单的方法可以避免循环类型提示:不要使用from导入,而使用from __future__ import annotations或 字符串注释。
# foo.py
from __future__ import annotations
import bar
class Foo:
bar: bar.Bar
Run Code Online (Sandbox Code Playgroud)
# bar.py
import foo
class Bar:
foo: "foo.Foo"
Run Code Online (Sandbox Code Playgroud)
这种导入方式是“延迟评估”的,而使用from foo import Foo会强制 Python 运行整个模块以立即在导入行foo获取最终值。Foo如果您还需要在运行时使用它,例如如果需要在函数/方法中使用foo.Foo或,那么它非常有用,因为您的函数/方法应该只被调用一次并且可以使用。bar.Barfoo.Foobar.Bar
更大的问题是你的类型开始时并不理智.MyMixin做出一个硬编码的假设,它将被混合Main进来,而它可以被混合到任意数量的其他类中,在这种情况下它可能会破坏.如果你的mixin被硬编码以混合到一个特定的类中,你也可以将方法直接写入该类而不是将它们分离出来.
要通过合理的输入正确地执行此操作,MyMixin应该使用Python语言对接口或抽象类进行编码:
import abc
class MixinDependencyInterface(abc.ABC):
@abc.abstractmethod
def foo(self):
pass
class MyMixin:
def func2(self: MixinDependencyInterface, xxx):
self.foo() # ? mixin only depends on the interface
class Main(MixinDependencyInterface, MyMixin):
def foo(self):
print('bar')
Run Code Online (Sandbox Code Playgroud)
对于仅在导入类以进行类型检查时陷入困境的人们:您可能希望使用前向引用(PEP 484-类型提示):
当类型提示包含尚未定义的名称时,该定义可以表示为字符串文字,稍后再解析。
所以代替:
class Tree:
def __init__(self, left: Tree, right: Tree):
self.left = left
self.right = right
Run Code Online (Sandbox Code Playgroud)
你做:
class Tree:
def __init__(self, left: 'Tree', right: 'Tree'):
self.left = left
self.right = right
Run Code Online (Sandbox Code Playgroud)
原来我最初的尝试也非常接近解决方案。这是我目前使用的:
# main.py
import mymixin.py
class Main(object, MyMixin):
def func1(self, xxx):
...
# mymixin.py
if False:
from main import Main
class MyMixin(object):
def func2(self: 'Main', xxx): # <--- note the type hint
...
Run Code Online (Sandbox Code Playgroud)
请注意if False永远不会导入的 import inside语句(但 IDE 无论如何都知道它)并使用Main该类作为字符串,因为它在运行时未知。
| 归档时间: |
|
| 查看次数: |
11907 次 |
| 最近记录: |