15.Python Package目录及打包并发布到PyPI

news/2024/7/19 12:37:32 标签: python, 爬虫, java

欢迎访问个人网络日志🌹🌹知行空间🌹🌹


文章目录

    • 0.基本介绍
    • 1.`__init__.py`文件
      • 1.1 Regular Package
      • 1.2 namespace package
    • 2.`Python Package`工程
      • 2.1 安装及打包并发布到pypi
      • 2.2 将`Python`文件编译成`.so`
    • 3.包的搜索路径
    • 参考资料

0.基本介绍

Python的强大之处就是它的丰富的开源包,如何开发一个自己的Python Package并将其发布到Pypi呢?在这里记录一下完整的过程。

1.__init__.py文件

python 中的包分成两种,一种是普通包regular package,一种是命名空间包namespace package

1.1 Regular Package

普通包是指包含一个 __init__.py文件的普通目录,在Python 3.2及之前的版本中一直使用的都是这种包。普通包在导入的时候,会隐式自动调用包中的__init__.py文件,__init__.py中定义的对象,变量都会被限制在包名的命名空间中。

如下形式的包:

parent/
    __init__.py
    one/
        __init__.py
    two/
        __init__.py
    three/
        __init__.py

导入parent.one包时,会自动执行parent/__init__.pyparent/one/__init__.py,导入其他的包时情况也类似。

总结,只需要记住,__init__.py是包导入时最先执行的文件

_init__.py中还有一个重要的变量,__all__, 它用来将模块全部导入,也就是支持使用from package import *

python">__all__ = ['os', 'sys', 're', 'urllib']

1.2 namespace package

命名空间包是指一种特殊的 Python 包,在Python 3.3之后引入,它不包含__init__.py文件,而是由一个或多个不同的目录组成,每个目录都可以包含一个或多个模块。

如有一个命名空间包namespace packagensp,在目录/xx/test_cpp/mypkg/ns/xx/test_cpp/mypkg/pkg下各有一个nsp是文件夹,其中分别包含nsp1.pynsp2.py文件,将路径/xx/test_cpp/mypkg/pkg/xx/test_cpp/mypkg/ns加入到sys.path中,就可以通过import nsp导入文件夹了。

python"># /xx/test_cpp/mypkg/nsa/nsp/nsp1.py
def print_nsp1():
     print(f"nsp1")

# /xx/test_cpp/mypkg/nsa/nsp/nsp2.py
def print_nsp2():
     print(f"nsp2")

sys.path.insert(-1, "/xx/test_cpp/mypkg/nsa")
sys.path.insert(-1, "/xx/test_cpp/mypkg/nsb")

import nsp # 这里会将两个路径下的nsp合成一个
nsp.print_nsp1()
nsp.print_nsp2()

注意两个文件夹nsp中都不能包含nsp.py,否则无法导入另外一个。

使用 namespace package命名包时,Python包的搜寻规则为,先搜寻常规的package,再搜寻module文件,然后若搜索到不包含__init__.py文件的目录即namespace package会先记录其路径,待sys.path路径搜寻完毕,若regular packagemodule中都没有而namespace package中有,就导入namespace pakge

2.Python Package工程

一个Python Package工程目录示例:

packaging_tutorial/
├── LICENSE
├── pyproject.toml
├── README.md
├── src/
│   └── packaging_tutorial/
│       ├── __init__.py
│       └── example.py
└── tests/
  • tests文件夹中放的是包的单元测试文件
  • pyproject.toml文件告诉前端打包工具如pip/build等应该使用哪个后端工具如setuptools/ Hatchling等创建工程的发布包。
python">[build-system]
# requires是构建包需要的依赖,不需要手动的安装,前端工具如`pip`等会自动安装
requires = ["setuptools", "setuptools-scm"]
build-backend = "setuptools.build_meta"

除了指定编译系统之外,还需要为包添加元数据metadata,依赖dependencies和内容contents等,这些内容可以保存在pyproject.toml中,也可单独写到setup.py或者setup.cfg文件中。

如‵setup.py`

python">
from setuptools import setup

setup(
    name='mypackage',
    version='0.0.1',
    install_requires=[
        'requests',
        'importlib-metadata; python_version == "3.8"',
    ],
)

或者setup.cfg:

python">[metadata]
name = mypackage
version = 0.0.1

[options]
install_requires =
    requests
    importlib-metadata; python_version < "3.8"s

setup方法中接受的参数以及含义介绍可以参考这里

setup.py/setup.cfgpyproject.toml文件有重复配置的内容时,优先使用pyproject.toml中的内容。

2.1 安装及打包并发布到pypi

  • 开发模式安装本地包
python">pip install --editable .
  • 打包包文件,执行完成后,在包路径下生成dist文件夹,其中有打包好的文件
python">python -m build

# dist
# ├── mypkgg-0.0.1-py3-none-any.whl
# └── mypkgg-0.0.1.tar.gz
  • 将包上传到pypi
python"># 1.先安装twine包

pip install twine

python3 -m twine upload --repository testpypi dist/*

输入pypi的账号,密码后就可以将包上传到pypi数据库中了,网站上访问显示如下:

在这里插入图片描述

  • 如果git仓库是package,还可以通过如下形式安装:
pip install -q git+https://github.com/lx-r/mypkg.git

python中,为了避免setup.py的误执行,现在更推荐使用setup.cfg

上面包中的文件都是手动创建的,其实每个Python包都需要包含上述文件,如此就可以使用模板来创建Python包,常用的工具有cookiecutter等。

2.2 将Python文件编译成.so

需要使用cython

python">pip install cython

setup.py文件中设置

python">from Cython.Build import cythonize
setup(ext_modules = cythonize(["hello1.py", "hello2.py"]))

执行编译命令:

python setup.py build_ext

值得注意的是这里打包的.so文件只能适用于同样平台的同样python版本。

3.包的搜索路径

先搜寻built-in模块module,内建模块在变量sys.builtin_module_names中。

然后到sys.path路径中搜寻,sys.path中包含以下部分,

  • 当前路径
  • 环境变量PYTHONPATH
  • 缺省的安装路径如site-packages

关于包内的导入方式,当包中包含子包的时候,可以使用绝对路径导入,也可以通过相对路径的方式导入:

# mypkg
├── __init__.py
├── mypkg.py
└── utils
    ├── __init__.py
    └── utils.py

导入方式:

python">from .utils import utils
# in utils.py
from ..mypkg import xx

值得注意的是,相对路径的引入方式都是基于当前模块的名称__name__的,而在主模块中其__name__==__main__,因此在主模块函数中必须使用绝对导入方式。

参考资料

  • 1.https://docs.python.org/3/reference/import.html#packages
  • 2.https://www.cnblogs.com/chaoguo1234/p/9350396.html
  • 3.https://docs.python.org/3/tutorial/modules.html#the-module-search-path
  • 4.https://setuptools.pypa.io/en/latest/userguide/quickstart.html
  • 5.https://zhuanlan.zhihu.com/p/265462717

http://www.niftyadmin.cn/n/312846.html

相关文章

RabbitMQ入门案例及简单工程搭建

环境的搭建 这里是用Maven工程搭建的基础环境项目&#xff0c;这里的dome_rabbitmq就是父工程。 子工程 publisher&#xff1a;消息发布者&#xff0c;将消息发送到队列queueconsumer&#xff1a;订阅队列&#xff0c;处理队列中的消息 父工程的pom文件依赖 <?xml ver…

Unity大面积草地渲染——4、对大面积草地进行区域剔除和显示等级设置

目录 1、Shader控制一棵草的渲染 2、草地的动态交互 3、使用GPUInstancing渲染大面积的草 4、对大面积草地进行区域剔除和显示等级设置 Unity使用GPU Instancing制作大面积草地效果 大家好&#xff0c;我是阿赵。 这里开始讲大面积草地渲染的第四个部分&#xff0c;对大面积草地…

C/C++每日一练(20230508) 链表专题2

目录 1. 相交链表 &#x1f31f;&#x1f31f; 2. 排序链表 &#x1f31f;&#x1f31f; 3. 重排链表 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. …

简单记忆clarke和park坐标变换

简单记忆clarke和park坐标变换 简介 想用简单的办法把这些变换矩阵写出来&#xff0c;需要的时候可以使用&#xff0c;不用再去翻书&#xff08;当然完全记住还是更快一些&#xff09;。只是自己用来记忆这些变换的方法。 具体可以参考&#xff1a;手撕系列&#xff08;2&am…

数据校验的艺术:从奇偶校验到CRC校验与海明校验

目录标题 一、引言 (Introduction)1.1 校验码的重要性&#xff08;The Importance of Check Codes&#xff09;1.2 校验码的基本工作原理&#xff08;The Basic Working Principle of Check Codes&#xff09;1.3 对本文的概述&#xff08;Overview of This Article&#xff09…

探寻Spring MVC的奥秘:内部组件与工作流程详解

Spring MVC是一个基于MVC架构模式的Web框架&#xff0c;是Spring框架的一个组件。它提供了一套Web应用程序开发的全面解决方案&#xff0c;包括从请求到响应的处理流程、处理请求的控制器、视图解析器、国际化和验证器等。 在这篇文章中&#xff0c;我们将介绍Spring MVC框架的…

linkindList源码分析

前言 LinkedList &#xff0c;基于节点实现的双向链表的 List &#xff0c;每个节点都指向前一个和后一个节点从而形成链表。 LinkedList集合同时具有List集合和Queue集合的基本特征 类图 如下 1 个接口是少于 ArrayList 的&#xff1a; java.util.RandomAccess 接口&#xff…

线性结构-队列

队列是一种先进先出First In Fisrt Out,FIFO的线性表。 与一般的数组和链表不同&#xff0c;队列要求所有的数据只能从一端进入&#xff0c;从另一端离开。 输入进入的一端叫队尾rear&#xff0c;数据离开的一端叫队头front。 数据只能从队尾进入队列&#xff0c;从队头离开队…