【问题标题】:Structuring a python project构建一个python项目
【发布时间】:2019-06-22 20:34:32
【问题描述】:

我需要知道如何设置 __init__.py 和导入,以便构建一个可以在整个包中使用完全限定名称的 python 项目。

该包将包含许多可能包含冲突名称的子包。包中包含的类将互为子类并包含对彼此的引用。该项目将被生成,因此使用完全限定名称将使生活变得更加简单。

这个示例项目代表了我的目标结构,但只包含一个子项目,而 IDE 似乎对它在运行时失败感到满意。

MyPackage/__init__.py

import SubPackage as SubPackage

MyPackage/SubPackage/__init__.py

from .FileB import ClassB
from .FileA import ClassA

MyPackage/SubPackage/FileA.py

from __future__ import absolute_import
import MyPackage


class ClassA(MyPackage.SubPackage.ClassB):
    thingA: 'MyPackage.SubPackage.ClassA'
    thingB: MyPackage.SubPackage.ClassB

    def __init__(self):
        self.thingA = None
        self.thingB = None

    def test(self):
        self.thingA = MyPackage.SubPackage.ClassA()
        self.thingB = MyPackage.SubPackage.ClassB()

MyPackage/SubPackage/FileB.py

from __future__ import absolute_import
import MyPackage


class ClassB(object):
    nextB: 'MyPackage.SubPackage.ClassB'

    def __init__(self):
        self.nextB= None

    def test(self):
        self.nextB= MyPackage.SubPackage.ClassB()

test.py

import MyPackage

x = MyPackage.SubPackage.ClassA()

错误

  File "C:\temp\Test.py", line 3, in <module>
    import GeneratedLx
  File "C:\temp\MyPackage\__init__.py", line 1, in <module>
    import Bs as Bs
  File "C:\temp\MyPackage\SubPackage\__init__.py", line 12, in <module>
    from .FileA import ClassA
  File "C:\temp\MyPackage\SubPackage\FileA.py", line 5, in <module>
    class ClassA(MyPackage.SubPackage.ClassB):
AttributeError: module 'MyPackage' has no attribute 'SubPackage'

【问题讨论】:

  • 为什么需要完全限定所有内容?为什么还有这么多模块?如果问题中的代码具有代表性,则您的模块非常短。您通常只在每个模块中包含几个类,从而避免大量导入。有理由不这样做吗?此外,除非存在名称冲突,否则最好使用较短的引用。
  • 可能有 100 个模块和最多约 5 个子包。子包中的类可以相互关联(从另一个子包中的类派生)并使用其他子包中的类。因此存在名称冲突的可能性,因此最好对名称进行完全限定。
  • 离开名称链 MyPackage 应该使您的变量足够合格以避免冲突,并消除引用问题(我认为是鸡和蛋)。在“FileA”和 B 中,只需 from MyPackage import Submodule 并跳过名称中的 MyPackage.。 FTR 调用这些长属性链可能会对性能产生明显影响(attr 调用并不快)。
  • @Sproty 听起来你真的会从将你的模块合并到更少的模块中受益匪浅。 特别是当类相互依赖时,将它们包含在同一个模块中要简单得多。模块和包不用于创建详细的分类。它们用于提供一起工作的大量函数、类和变量,或者用于避免名称冲突。如果你在一个包中有数百个模块,那么你可能正在做一些非 Pythonic 的事情。在您的顶级包中,考虑别名而不是完全限定。
  • 源数据(将生成这些类)被分解为多个“命名空间”,因此相同的名称可能出现在 2 个命名空间中。我认为 SubPackage 将是每个命名空间的好容器。如果每个命名空间中的类是独立的,那么每个子包可以是一个单独的模块,但是每个子包中的类之间可能存在相互关系,即 nsA:cls1 派生自 nsB:cls2 派生自 nsA:cls3。一种保证它们以正确顺序定义的方法是拆分 1 个类/模块,除非 Python 可以进行前向声明?

标签: python python-packaging


【解决方案1】:

您已经不能在SubPackage 级别出现名称冲突,因此添加MyPackage 完全是多余的,并且与您尝试使用它的方式不同。这可能是由于名称被绑定或其他原因,但最终不应该在您需要它时出现实例。这样您就可以稍微编辑文件:"FileA.py""FileB.py":

FileA.py

from __future__ import absolute_import
from MyPackage import SubPackage


class ClassA(SubPackage.ClassB):
    thingA: 'SubPackage.ClassA'
    thingB: SubPackage.ClassB

    def __init__(self):
        self.thingA = None
        self.thingB = None

    def test(self):
        self.thingA = SubPackage.ClassA()
        self.thingB = SubPackage.ClassB()

FileB.py

from __future__ import absolute_import
from MyPackage import SubPackage


class ClassB(object):
    nextB: 'SubPackage.ClassB'

    def __init__(self):
        self.nextB= None

    def test(self):
        self.nextB= SubPackage.ClassB()

import 语句也等效于from .. import Subpackage,如果需要,使用相对导入而不是绝对导入。在风格上,我倾向于使用相对导入来帮助我快速找出哪些导入是我的项目的一部分,哪些是外部依赖项。

【讨论】:

  • 奇怪的是,即使添加了第二个 SubPackage,这似乎也有效。我不得不说,我不是很理解原来的错误,但这看起来是一个可行的解决方案。
  • @Sproty 我不认为包打算在顶层导入自己。你必须至少向下一层(即:子包级别)。提升一个级别的唯一原因是导入一个完全独立的包。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-30
  • 2016-01-26
  • 2020-10-10
  • 2016-03-30
  • 2019-06-10
  • 2019-10-14
  • 2013-01-03
相关资源
最近更新 更多