【问题标题】:python library directory structure to separate codepython库目录结构来分隔代码
【发布时间】:2021-06-28 02:07:29
【问题描述】:

我希望有以下目录结构:

project_name (unfortunate, I did not think to name the git repo something different)
|  ... 
|
|--project_name
|  |-- __init__.py
|  |-- module1
|  |   |-- __init__.py
|  |   |-- pyfile1.py
|  |        #contains class1 which pulls from class2 and class1
|  |-- module2
|  |   |-- __init__.py
|  |   |-- pyfile2.py
|  |        #contains class2
|  |-- module3
|      |-- __init__.py
|      |-- pyfile3.py
|           #contains class3
|--tests
|  |--test1   
   ...

上面,当我把它扔到 github 并从 github 安装它时,我注意到子模块是单独安装的,而不是在 project_name 下一起安装。

我想简洁地访问第 1 类,而第 1 类从第 2 类和第 3 类中提取。目前,我让他们互相调用很好,我相信他们正在通过我的测试目录中包含的 pytest 进行测试。即……

# in class1
from project_name.module2.pyfile2 import class2
from project_name.module3.pyfile3 import class3

# in test1
from project_name.module1.pyfile1 import class1

我希望能够像 from project_name.module1 import class1 一样调用说 class1 还是必须在此结构下使用 from project_name.module1.pyfile1 import class1?我知道这可能有点荒谬,但我已经尝试了一些组织迭代,即删除子模块结构并简单地将它们全部放在 project_name 下,并带有一个 __init__.py。但我现在想要某种关注点分离,所以我想知道如何正确地做到这一点。

我认为是多个__init__.pys 导致单独的模块与我的setup.py 一起安装,它正在查看project_name 目录,而不是仅仅安装project_name 目录,然后我可以访问像我对测试所做的子模块:


import setuptools
import re
import os.path
import sys

with open("README.md", "r") as fh:
    long_description = fh.read()

def read(filename):
    return open(os.path.join(os.path.dirname(__file__), filename)).read()

version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', read('project_one/__init__.py'), re.MULTILINE).group(1)

install_requires=['pandas>=1.0.0']
include_packages=['project_one']
tests_require=['pytest>4.0', 'pytest-pylint']
setup_requires=['pytest-runner', 'pytest-pylint']

setuptools.setup(
    name="project_one"
    , version=version
    , license='LICENSE.txt'
    , author=author
    , author_email=email
    , description=description
    , long_description=long_description
    , long_description_content_type="text/markdown"
    , url=url
    , packages=setuptools.find_packages('project_name', exclude=['tests'])
    , classifiers=[
        'Development Status :: 3 - Alpha',
        'Intended Audience :: Developers',
        'Topic :: Software Development :: Build Tools',
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7',
        'Programming Language :: Python :: 3.8',
    ]
    , python_requires='>3.0, !=3.1.*, !=3.2.*, !=3.3.*'
    , install_requires=install_requires
    , tests_require=tests_require
    , setup_requires=setup_requires
    #, extras_require={'pandas': ['pandas>=0.14.0']}
)

那么我该如何停止子目录的安装,让它安装 project_name 目录,并正确地构建目录和代码来做到这一点。

另外,我的子目录__init__.py 是空的。 project_name__init__.py 有以下内容,但如果没有安装project_name 目录,则无用:

# -*- coding: utf-8 -*-
# PEP 8 Style Guide for Python Code.
# https://www.python.org/dev/peps/pep-0008/

import logging

# Major.Minor.Patch 
__version__ = '0.7.0'
__author__ = 'name'

from .module1.pyfile1 import class1
from .module2.pyfile2 import class2
from .module1.pyfile3 import class3

# Set default logging handler to avoid "No handler found" warnings.
try:  # Python 2.7+
    from logging import NullHandler
except ImportError:
    class NullHandler(logging.Handler):
        """For future error handling purposes"""
        def emit(self, record):
            pass

logging.getLogger(__name__).addHandler(NullHandler())

【问题讨论】:

  • 澄清一些命名:Python 文件是一个模块,带有__init__.py 的文件夹是一个
  • 感谢您的更正,这很有帮助。在这些方面更有意义......这三个包正在安装在站点包中。

标签: python python-3.x pip anaconda


【解决方案1】:

您想要的结构看起来很奇怪,因为文件名只会增加模块名称的混淆。每个模块都按照类命名,它看起来更自然(并且可以按您的预期工作),例如

.
└── project_name
    ├── __init__.py
    ├── class1.py
    ├── class2.py
    └── class3.py

随着您的模块变得越来越复杂,您可能希望在内部将它们分解为文件,但不要更改任何访问它们的代码。为此,您可以使用 __init__.py 来“发布”内容以方便(并保持您的调用协议相同),因此:

.
└── project_name
    ├── __init__.py
    ├── class1
    │   ├── __init__.py
    │   ├── class1.py
    │   └── utils.py
    ├── class2.py
    └── class3.py

您可以在class1/__init__.py 中输入from .class1 import <whatever>,这样您的应用程序的其余部分就不需要更改其导入。

使用这种方法,您可以从一个模块(文件)开始,然后在开发过程中将关注点分开时将其扩展为一棵包树。

对于您的设置,您在 project_name 中查找包,因此您需要从 find_packages 中删除第一个参数。

【讨论】:

  • 感谢您的反馈。我已遵循这些建议,并且我相信我更了解这一点。所以,我从 find_packages 中删除了“project_one”,它说“project_one/project_one”不存在。此外,“模块”1、2 和 3 是单独安装的,而不是在“project_one”下,这会导致导入中断。
  • 啊...原来我的 setup.cfg 正在接管?我删除了它,因为它是该项目最近添加的内容之一(第一个 tbh)。你能解释一下吗?它只有package dir = project_one。哦,但是在 project_one 中……没有 project_one。明白了。
猜你喜欢
  • 1970-01-01
  • 2011-08-06
  • 1970-01-01
  • 2012-11-04
  • 2010-09-07
  • 2010-11-26
  • 2014-10-06
  • 2014-08-05
  • 1970-01-01
相关资源
最近更新 更多