首页 > 编程语言 >Python module 的相对导入

Python module 的相对导入

时间:2024-09-22 13:23:33浏览次数:10  
标签:__ Python py module cat pet 导入 petstore import

Python module 的相对导入

python module relative import

目录

Created: 2024-09-22T11:16+08:00
Published: 2024-09-22T13:20+08:00

Category: Python

第一次编写 Python package 时候,很可能会需要不同文件夹下的 python 文件相互 import。
如果不了解 Python 的 relative import 机制,很可能会导致如下两种错误:

ModuleNotFoundError: No module named 'xxx'
ImportError: attempted relative import with no known parent package

本文通过一个 petstore 例子,告诉大家如何写 package。

有四个需求:

  1. Cat 和 Dog 两个类,继承自 Pet 类
  2. 我们需要在 main.py 中自定义类继承 Pet
  3. 我们需要在 main.py 中使用 Cat
  4. cat.py 里面有一个 if __name__ == "__main__,我们可以直接执行 cat.py

项目结构

├─main.py
│
└─petstore
    │  __init__.py
    │
    ├─pet
    │  │  cat.py
    │  │  dog.py
    │  │  pet.py
    │  └─ __init__.py
    │
    └─store
           __init__.py

main.py

# main.py

print("we are running: ", __name__)

import sys

from petstore.pet import Pet
from petstore.pet.cat import Cat


class Bird(Pet):
    def __init__(self) -> None:
        super().__init__()

    def eat(self):
        print("bird eat")


if __name__ == "__main__":
    c = Cat()
    c.eat()

    b = Bird()
    b.eat()

pet.py

# pet.py

import abc


class Pet(abc.ABC):
    def __init__(self) -> None:
        pass

    @abc.abstractmethod
    def eat(self):
        pass

cat.py

# cat.py
print("importing cat")
print("cat.py.__name__:", __name__)
print("done\n")

from .pet import Pet # <- attention here!!!


class Cat(Pet):
    def __init__(self) -> None:
        pass

    def eat(self):
        print("cat eat")


if __name__ == "__main__":
    c = Cat()
    c.eat()

dog.py

print("importing dog")
print("dog.py.__name__:", __name__)
print("done\n")

from .pet import Pet


class Dog(Pet):
    def __init__(self) -> None:
        pass

    def eat(self):
        print("dog eat")

pet/__init__.py

"""
这个包处理宠物管理功能。
"""

from .pet import Pet
from .cat import Cat
from .dog import Dog

__all__ = ['Pet', 'Cat', 'Dog']

ModuleNotFoundError: No module named 'pet'

如果将 from .pet import Pet 写作 from pet import Pet
并且直接在项目 根目录 python ./main.py,就会报这个错。

因为 python 文件直接作为命令行参数执行的时候,
解释器就认为其是一个 module 的 root[1]没有传递任何关于 petstore 的 package structure
当执行到 cat.py 中的 from pet import Pet 时候,
就会从 sys.path 中查找 pet,目前的路径是根目录,没有 pet,所以找不到就报错。

solution 1

如果这时候,我们在 main.py 中加上:

import sys
sys.path.append("./petstore/pet")

就可以让 cat.pyfrom pet import pet 生效。

solution 2

直接使用 sys.path 毕竟不好,将路径 hard encode 到了文件中,
更好的写法是写作 from .pet import Pet
这样 python main.py 时候,可以正确解析 petstore package 的结构。

ImportError: attempted relative import with no known parent package

这个错误发生在使用了 relative import 后,
直接运行使用 relative import 的 python 文件。
python .\petstore\pet\cat.py

python .\petstore\pet\cat.py
importing cat
cat.py.**name**: **main**
done

Traceback (most recent call last):
File "~\petstore\pet\cat.py", line 5, in <module>
from .pet import Pet
ImportError: attempted relative import with no known parent package

因为直接运行的文件将视作 package 的 root,所以没法 relative import。

solution

想要直接运行 cat.py,可以使用命令 python -m petstore.pet.cat

关键是参数 -m

> python -m petstore.pet.cat

importing cat
cat.py.__name__: petstore.pet.cat
done

importing dog
dog.py.__name__: petstore.pet.dog
done

<frozen runpy>:128: RuntimeWarning: 'petstore.pet.cat' found in sys.modules after import of package 'petstore.pet', but prior to execution of 'petstore.pet.cat'; this may result in unpredictable behaviour
importing cat
cat.py.__name__: __main__
done

cat eat

可以看到 petstore.pet.cat 这个 module 被 解析了两次,第一次其 __name__petstore.pet.cat,第二次为 __main__

总之,不应该在 module 内部运行 script[2]

总结

那么正确的做法应该是什么呢?

在同一个 package 中,只使用 relative import
要测试 package 中的 module,在外部进行测试,module 内不要有 if __name__ == "__main__"

复述下需求的解决方法:

├─main.py
│
└─petstore
    │  __init__.py
    │
    ├─pet
    │  │  cat.py
    │  │  dog.py
    │  │  pet.py
    │  └─ __init__.py
    │
    └─store
           __init__.py
  1. Cat 和 Dog 两个类,继承自 Pet 类
    使用 from .pet import Pet
  2. 我们需要在 main.py 中自定义类继承 Pet
    将 petstore 视作一个 package,直接 from petstore.pet import Pet
  3. 我们需要在 main.py 中使用 Cat
    将 petstore 视作一个 package,直接 from petstore.pet.cat import Cat
  4. cat.py 里面有一个 if __name__ == "__main__,我们可以直接执行 cat.py
    因为 cat.py 中已经使用了 relative import 所以使用命令 python -m petstore.pet.cat 来运行

  1. https://stackoverflow.com/a/73149/20752995 ↩︎

  2. https://stackoverflow.com/a/8195271/20752995 ↩︎

标签:__,Python,py,module,cat,pet,导入,petstore,import
From: https://www.cnblogs.com/dutrmp19/p/18425194

相关文章

  • python+flask计算机毕业设计家庭财务管理系统APPy(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景在当今社会,随着家庭经济活动的日益复杂和多元化,个人及家庭对于财务管理的需求日益增长。传统的手工记账方式已难以满足现代家庭对财务透明......
  • python+flask计算机毕业设计基于物联网技术的水质实时监测系统设计与实现(程序+开题+论
    文件加密系统的设计与实现tp835本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着工业化进程的加速和人口的不断增长,水资源的保护与监测日益成为全球关注的重大课题。水质污染问题不仅......
  • python+flask计算机毕业设计快递代取小程序(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景在当今社会,随着电子商务的蓬勃发展,快递业务量急剧增长,成为了人们日常生活中不可或缺的一部分。然而,随之而来的“取件难”问题也日益凸显,尤......
  • python+flask计算机毕业设计+Vue的残疾人再就业系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着社会经济的快速发展与人口老龄化的加剧,残疾人群体作为社会的重要组成部分,其就业问题日益凸显。传统就业市场往往因信息不对称、技能不......
  • python+flask计算机毕业设计+vue的服装售后服务系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着电子商务的蓬勃发展,服装行业作为其中的重要组成部分,其售后服务质量已成为影响消费者购买决策的关键因素之一。传统的服装售后服务模式......
  • python+flask计算机毕业设计教师工作量统计系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景在高等教育快速发展的今天,教师作为教育的核心力量,其工作量的准确统计与评估成为了高校管理中不可或缺的一环。传统的教师工作量统计方式往......
  • python+flask计算机毕业设计基于微信小程序的垃圾分类系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着城市化进程的加快和居民生活水平的提高,垃圾产生量急剧增加,垃圾分类成为解决城市垃圾处理难题、促进资源循环利用的关键举措。然而,传统......
  • python+flask计算机毕业设计体检预约小程序(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着健康意识的不断提升和医疗技术的快速发展,人们对健康管理的需求日益增长。传统的体检预约方式往往存在流程繁琐、信息不对称、预约效率......
  • python+flask计算机毕业设计基于物联网技术的水质实时监测系统设计与实现(程序+开题+论
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着工业化进程的加速和人口的不断增长,水资源的污染问题日益严峻,成为制约经济社会可持续发展的重大瓶颈。传统的水质监测方法存在时效性差......
  • python+flask计算机毕业设计数据库加密系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,数据已成为企业和个人最宝贵的资产之一。然而,数据泄露和非法访问的风险也随之急剧增加,给个人隐私、企业安全乃至国......