在这个问题中如何将类的函数分离到多个文件中?最重要的答案是建议使用
from method_file import method
在类定义内部,在单独的文件中定义类方法。然而,对于像这样的类
my_number.py
class MyNumber:
def __init__(self):
self.x = 5
from my_method import my_method
my_method.py
def my_method(self):
print(self.x)
对于IDE来说,self
指的是MyNumber
对象是不清楚的。因此,代码完成(例如self.x
)在my_method
中不可用。self
的类型提示可以解决此问题,即
my_method.py
from my_number import MyNumber
def my_method(self: MyNumber):
print(self.x)
但这导致了循环导入。
对于这种情况,有什么变通方法或最佳实践吗?
有一种方法将__future__
导入与if TYPE_CHECKING
子句相结合,以在运行时忽略类型注释;进口;仅从IDE的角度来看代码,以便可以完成代码。
示例:
my_number.py
class MyNumber:
def __init__(self):
self.x = 5
from my_method import my_method
my_method.py
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from my_number import MyNumber
def my_method(self: MyNumber):
print(self.x)
使用from __future__ import annotations
,我们推迟了对类型提示的评估——换句话说,即使我们实际上没有导入MyNumber
,我们也可以键入提示my_method
。这个行为本来是Python 3.10中的默认行为,但它被推迟了,所以我们现在需要这个导入。
现在,根据您的编辑器/IDE,您仍然会收到一条警告,抱怨MyNumber
没有定义,并且它的方法/属性可能不会显示在自动完成中。以下是TYPE_CHECKING
的作用:这只是一个恒定的False
值,这意味着我们的子句是:
if False:
from my_number import MyNumber
换句话说,我们是";欺骗;IDE认为我们正在导入MyNumber
,但实际上这一行从未执行过。因此,我们完全避免了循环进口。
这可能会让人觉得有点棘手,但它很有效:-)TYPE_CHECKING
常量的全部目的是允许类型检查器完成他们的工作,而不是在运行时实际导入代码,并且以一种清晰的方式来完成(Python的Zen:应该有一种——最好只有一种——明显的方法来完成)。
这种方法在PyCharm中一直适用于我,我不确定其他IDE/编辑器。
对于这种情况,有什么变通方法或最佳实践吗?
最佳做法是不要这样做。如果方法实现是特定于类的,那么它应该是类定义的一部分。
如果一个方法不是特定于类的,则应在所有有效类型中定义它。协议适合表达这一点:
from typing import Protocol, Any
class HasX(Protocol):
x: Any # might need a TypeVar for complex cases
def my_method(self: HasX):
print(self.x)
如果一个方法扩展了一个独立于其定义的类,则不应对其进行修补。使用functools.singledispatch
从外部定义单个调度函数,这些函数在逻辑上类似于方法:
from functools import singledispatch
from my_number import MyNumber
# not imported into MyNumber
@singledispatch
def my_method(self):
raise NotImplementedError(f"no dispatch for {type(self}")
@my_method.register
def _(self: MyNumber):
print(self.x)
通常,self关键字用于表示类的实例。键入提示self是没有意义的。其次,如果函数不是是MyNumber对象的类的方法,则不能通过self访问实例变量x。
我建议两个选项来实现您想要的。您可以接受MyNumber对象作为my_method()函数的参数,也可以创建一个新类并继承MyNumber类。确保文件在同一目录中,否则更新文件2中的import语句。
选项#1
class MyNumber:
def __init__(self):
self.x = 5
def my_method(my_number: MyNumber):
print(my_number.x)
my_method(MyNumber())
选项#2
#my_number.py
class MyNumber:
def __init__(self):
self.x = 5
#my_method.py
from my_number import MyNumber
class MyMethod(MyNumber):
def __init__(self):
super().__init__()
def my_method(self):
print(self.x)
MyMethod().my_method()
我认为您在python中遇到了有关面向对象概念的问题。您的";my_method";函数不需要";self:MyNumber";作为一个参数,事实上,您需要创建MyNumber类的一个对象,因此该类将具有一个属性,即;x〃;由于您定义了";x〃;在MyNumber类的构造函数中。它看起来像这样:
#my_number.py
class MyNumber:
def __init__(self):
self.x = 5
#my_method.py
from my_number import MyNumber
def my_method():
mm = MyNumber()
print(mm.x)