Python 再次循环进口
我在python3.8中有一个模块结构,如下所示:Python 再次循环进口,python,python-3.x,circular-dependency,Python,Python 3.x,Circular Dependency,我在python3.8中有一个模块结构,如下所示: module |- __init__.py |- foo.py |- bar.py 与 #init.py from.foo导入foo from.bar导入栏 __全部uuu=['Foo','Bar',] 现在我想实现一个乘法foo*bar。所以我在写: #foo.py from.bar导入栏 Foo类: 定义初始化(自): self.value=5 定义多个(自身、其他): 如果不存在(其他,条形):提升值错误(“”) 返回self.val
module
|- __init__.py
|- foo.py
|- bar.py
与
#init.py
from.foo导入foo
from.bar导入栏
__全部uuu=['Foo','Bar',]
现在我想实现一个乘法foo*bar
。所以我在写:
#foo.py
from.bar导入栏
Foo类:
定义初始化(自):
self.value=5
定义多个(自身、其他):
如果不存在(其他,条形):提升值错误(“”)
返回self.value*other.number
及
#bar.py
from.foo导入foo
分类栏:
定义初始化(自):
self.number=2
定义多个(自身、其他):
如果不是isinstance(其他,Foo):提升值错误(“”)
返回其他*自我
不幸的是,这并不像预期的那样有效。在这种情况下,有没有办法进行类型检查?我知道我可以在
栏中导入Foo.\uuu mul\uuuu
——但这对我来说似乎很不整洁。需要时导入Foo:
#bar.py
分类栏:
定义初始化(自):
self.number=2
定义多个(自身、其他):
from.foo导入foo
如果不是isinstance(其他,Foo):提升值错误(“”)
返回其他*自我
在这种情况下,酒吧是已知的,所以没有更多的问题
开始编辑
好的,稍微有点粗糙,但是您可以在类之外定义\uuuuuuuuuuuuuuuuuuuuuuuuuuu
函数:
class Bar:
def __init__(self, value=10):
self.value = value
class Foo:
def __init__(self, value=5):
self.value = value
# def __mul__(self, other):
# return self.value * other.value
def mul_func(self, other):
if isinstance(other, Bar):
return self.value * other.value
raise ValueError('')
Foo.__mul__ = mul_func
a = Foo(5)
b = Bar(10)
c = Foo(20)
a*b
a*c # value error
编辑结束我有两种解决方案,要么使用基类的变通方法,要么使用
类型以外的其他方法来知道你做得对
编辑:我想知道最初的问题是什么。因为所有这些对我来说似乎都很棘手,或者我只是没有以一种好的方式看待问题。如果我们使用mybase.py
解决方案,为什么不为原始foo.py
和bar.py
使用单个文件呢。我想具体实施取决于你
解决方案1:基类
您的体系结构如下所示:
module
|- __init__.py
|- foo.py
|- bar.py
|- mybase.py
然后,您将拥有文件mybase.py
,例如
classmyfoobase:
通过
MyBarBase类:
通过
然后,在您的文件foo.py
和bar.py
中,您将拥有以下文件(我将只显示一个文件,因为很明显,另一个文件是什么样子的)
from.mybase导入MyFooBase,MyBarBase
分类栏(MyBarBase):
定义初始化(自):
self.number=2
定义多个(自身、其他):
如果不是isinstance(其他,MyFooBase):raise VALUETERROR(“”)
返回other.value*self.number
解决方案2:使用其他类型。
(请参见注释)将逻辑单元分隔为单独的包和模块可能很有用,但坚持一个文件只包含一个类几乎是教条。除非这些类很大,否则最好的解决方案是将它们固定在同一个模块中。考虑到您必须使用各种技巧来避免循环导入,那么能够为每个文件保留一个类真的值得吗
你可以做很多事情
只导入模块而不导入类(来自模块导入foo
),并通过模块引用类(例如isinstance(obj,foo.foo)
)
使用Python的“寻求宽恕,而不是许可”咒语。假设类的用户正确使用它们,并且操作数上存在相关属性。如果需要更多信息性错误消息,则可以在try:except AttributeError:
语句中包装属性回迁,这可能会引发首选错误。您必须确保在这样的try/except块中放入最基本的逻辑。例如,other_value=other.value
,然后在try/except块之外使用other_value
名称。这将停止try/except块在程序中隐藏可能的错误
只得到一个类来实现\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,这个类还可以实现\uuuuuuuuuuuuuuuuuuuuuuu。这允许所有实例检查只在其中一个类中完成,而不是同时在两个类中完成
str
和int
是标准库使用计算结果的示例(例如对于2*“a”
)。也就是说,当给定2*'a'
时,解释器首先尝试int.\uuuu mul\uuuu(2,'a')
。但是,这将返回NotImplemented
。因此,解释器随后将尝试使用str.\uu rmul\uu('a',2)
(返回'aa'
)。但是,只有当普通运算符函数返回NotImplemented
时,您才会看到他的行为。如果存在异常,则会传播此异常,而不是尝试\uuu rmul\uu
。在实现运算符的r
变量时,应注意self
将是表达式中的正确操作数,有时这可能会改变计算结果的方式(例如3-1!=1-3
)
第3点的例子
X类:
定义初始值(self,val):
self.val=val
Y类:
定义初始值(self,val):
self.val=val
def_mul(self,x):
如果不存在(x,x):
返回未执行
返回Y(self.val*x.val)
定义多个(自身、其他):
返回自我(其他)
定义(自身、其他):
返回自我(其他)
y=y(2)*X(3)#使用mul
断言isinstance(y,y)
断言y.val==6
使用rmul断言isinstance(X(3)*Y(2),Y)#
您可能需要检查其他
是否具有所需的属性,而不是检查其他
是否为类型X?例如,如果不是hasattr(其他,“值”):raise
?这是个好主意!在我的具体案例中,属性和get的乘法有点复杂,但这将是一种解决问题的“黑客”方法。也许还有更好的主意?因为这些课