说实话,Python的代码引用和组织真是一塌糊涂,处处是坑。
我们在执行Python代码的时候,解释器仅仅会将当前工作目录加入sys.path
,这就导致如果你的代码结构比较复杂,牵扯到多个子目录,那下面的代码互相引用就很麻烦了。
beyond top level error
。
实例
我们先来看我的一个项目代码结构:
项目目录下有三个层级平行的包carrier_pkg\land_pkg\takeoff_pkg
。他们中的代码会进行相对引用,比如:
#carrier.py
from abc import ABCMeta, abstractmethod
from ..land_pkg.land_mode import LandMode
from ..takeoff_pkg.takeoff_mode import TakeoffMode
class Carrier(metaclass=ABCMeta):
def __init__(self):
self._takeoffMode = None
self._landMode = None
self._name=""
看似没毛病,carrier.py
的上层目录是项目根目录,而且我们也创建了__init__.py
,可以看作一个模块,然后我们通过根目录去引用land_pkg
这个子模块,完全说的通。
但是我们一旦执行程序:
这就是我所说的beyond top-level error
。
我们再在debug窗口查看一下__package__
变量:
我们可以看到vikramaditya_carrier.py
的所属包是carrier_pkg
而非carrier_game_error.carrier_pkg
,这就意味着它所属的顶级包是carrier_pkg
而非carrier_game_error
,所以你要是想通过它去引用项目根目录的其它包,那是做梦。
我不清楚Python为什么会这样设计,明明这种代码结构在PHP或者Java中相当常见,但Python就是表现出了这样古怪的行为。
解决方法
解决方法其实也不是很难,你的顶级包不会到根目录是吧,那我给你多套一层就是了:
比如像上面这样,我们用一个包game_pkg
代替项目根目录去包三个子包。
相应的,项目根目录下的test.py
引用方式也要稍加修改:
from game_pkg.carrier_pkg.vikramaditya_carrier import VikramadityaCarrier
from game_pkg.carrier_pkg.queen_elizabeth_carrier import QueenElizabethCarrier
from game_pkg.carrier_pkg.nimitz_class_carrier import NimitzClassCarrier
from game_pkg.carrier_pkg.liao_ning_carrier import LiaoNingCarrier
lnCarrier = LiaoNingCarrier()
print(lnCarrier)
其它相对引用的部分不用做任何修改,我们再执行test.py
:
没有任何问题。
结论
如果你在使用相对引用的时候遇到了beyond top level error
,那就多加一层包。
参考资料:
文章评论