Python 导入自定义包的正确做法是什么? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
ztm0929
V2EX    Python

Python 导入自定义包的正确做法是什么?

  •  
  •   ztm0929
    ztm0929 2024-08-21 18:41:41 +08:00 9432 次点击
    这是一个创建于 415 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我是编程新手,正在练习爬虫项目,Python 到底如何导入包?

    xxx_project ├── README └── app ├── models.py ├── main.py └── crawler └── scraper_1.py └── scraper_2.py └── scraper_3.py 

    models 定义了数据库引擎和会话,我想让 scraper 能够与数据库交互,但是
    from ..models import func 会得到报错
    ImportError: attempted relative import with no known parent package

    from app.models import func 又会得到报错
    ModuleNotFoundError: No module named 'app'

    网上提到的在 app 目录下创建空白 __init__.py 似乎也没有效果,而 GPT 提到的将 app 目录添加到环境变量是最佳做法吗?还是说我这样的目录结构本身就是错的?

    第 1 条附言    2024-08-22 07:48:33 +08:00
    抱歉没讲清楚,目前同目录下的 main 是能够识别并导入 models 的。我是想要 scraper 去调用 models 进行数据库交互,暂时还不需要 main
    我现在临时的解决方法是把 models 移动到 crawler 目录下 hhh
    23 条回复    2024-08-24 10:56:28 +08:00
    mickerwx
        1
    mickerwx  
       2024-08-21 18:56:19 +08:00   1
    把你原来的导入删掉 然后在 scraper 里面写上 models 的模型名称,这个时候模型名称会报错,你把鼠标放上去,下面就会出现 import.... 点击一下 就可以了 前提你用的是 pycharm
    yanghanlin
        2
    yanghanlin  
       2024-08-21 18:59:06 +08:00 via Android   1
    试试 python -m app.main 而非 python app/main.py
    ztm0929
        3
    ztm0929  
    OP
       2024-08-21 19:04:20 +08:00
    @yanghanlin hhh 忘记说了,同目录下的 main 是可以导入 models 并成功识别的,不过-m 选项确实网上也有提到,我再试试看
    ztm0929
        4
    ztm0929  
    OP
       2024-08-21 19:05:01 +08:00
    @mickerwx 只用 VSCode 哈哈哈,不过我也试试这个方法~
    NoOneNoBody
        5
    NoOneNoBody  
       2024-08-21 19:21:38 +08:00   1
    给个我自用的方案,但我没编译过,不知道编译时会否出错
    在项目每个有 py 的子目录,都放一个空的,0 字节的 __init__.py ,项目根目录不需要
    然后,所有 import 都写为 from 一级子目录.二级子目录.xxx import ...,即使是内层的 py 也是这样写,总之就是从第一级开始写

    例如你这个,app 视为项目根目录,scraper_1.py 里面 import scraper_2 ,就要写成 from crawler import scraper_2 ,或者 import crawler.scraper_2 as ...,就是不要理会在哪一级或者是否同级,都要从第一级开始写 namespace
    然后,所有入口程序都应该放在项目根目录,你这个就是 app 这个目录。如果你想直接运行 scraper_1.py ,也要在 app 内另写一个 run_scraper_1.py 把 scraper_1 导入来运行
    darksword21
        6
    darksword21  
    PRO
       2024-08-21 19:29:25 +08:00 via iPhone   1
    官方文档 package and module
    assassing
        7
    assassing  
       2024-08-21 19:53:27 +08:00   1
    你需要在 app/__init__.py 中手动打入文件中的函数,例如:from .models.py import func ,注意文件名前面的点。然后在 scraper_1.py 中就能直接导入了:from app import func
    cnt2ex
        8
    cnt2ex  
       2024-08-21 19:54:40 +08:00   2
    python 会把被执行的脚本所在的目录插入到 sys.path 中,所以 import 都是相对于脚本所在位置计算的,所以一般入口脚本都是在项目根目录,其他东西都是相对于项目根目录。

    如果你不想把入口脚本放在根目录,就利用 PYTHONPATH ,在里面加上项目根目录。

    比如 PYTHOnPATH=/whatever/comes/before/xxx_project/app python main.py

    这样的 import 都可以写成
    ```
    from models import something
    from crawler.scrapper_1 import something
    ```

    而不管 main.py 在哪个位置
    forQ
        9
    forQ  
       2024-08-21 21:18:49 +08:00   1
    sys.path.append()

    sys.path.insert()
    chenqh
        10
    chenqh  
       2024-08-21 21:39:58 +08:00   1
    你把 main 移到 app 同层,就可以 from app.models import func
    NickLuan
        11
    NickLuan  
       2024-08-21 21:45:55 +08:00   1
    总结的到位
    @cnt2ex
    Sawyerhou
        12
    Sawyerhou  
       2024-08-21 22:13:02 +08:00   1
    楼上几层的观点+1 ,

    现有目录结构可以试试
    from models import func

    如果想从 app 导入,就要 append 路径到 sys ,
    不然 main 函数找不到 app
    y1y1
        13
    y1y1  
       2024-08-21 22:44:57 +08:00   1
    import 的根目录是入口文件的
    kanchi240
        14
    kanchi240  
       2024-08-21 23:55:59 +08:00   1
    https://docs.python.org/3/tutorial/modules.html#intra-package-references
    Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.
    sujin190
        15
    sujin190  
       2024-08-22 09:03:46 +08:00 via Android   1
    有__init__.py 文件的文件夹才是 python 的 package ,否则就是一个普通文件夹,而且如果你的 scraper 是个包含 main 的执行程序,此时是不能导入 models 的,因为不在 package 导入路径里,python import 的是 package 不是目录或者文件
    EndlessMemory
        16
    EndlessMemory  
       2024-08-22 10:14:08 +08:00   1
    添加当前路径到环境变量
    houzhiqiang
        17
    houzhiqiang  
       2024-08-22 14:00:01 +08:00
    根本原因是你要找到你的程序入口
    houzhiqiang
        18
    houzhiqiang  
       2024-08-22 14:07:46 +08:00   1
    run.py # from app import run_app
    |----app
    |----models.py
    |----__init__.py # def run_app
    |----crawler
    |---- a.py # from ..models import func

    $ python run.py

    |----app
    |----__main__.py # from . import run_app
    |----__init__.py # def run_app
    |----models.py
    |----crawler
    |----a.py # from ..models import func

    $ python -m app
    Maerd
        19
    Maerd  
       2024-08-22 17:29:17 +08:00
    楼上的很多都没说到点上,如果你是 pycharm ,可以不用配置,如果你是 vscode,需要将 PYTHONPATH 设为源代码根目录
    houzhiqiang
        20
    houzhiqiang  
       2024-08-22 18:01:28 +08:00   1
    @Maerd python xxx.py 会自动把当前目录加入 sys.path ,只需要正确找到顶层包就可以正确写出相对和绝对 import 的路径
    sys.path 第一个元素的值为
    python x.py # '.'
    python -m x.x # '.'
    python x/x.py # './x'
    ztm0929
        21
    ztm0929  
    OP
       2024-08-22 18:53:23 +08:00 via iPhone
    @Maerd 咦原来不同编辑器还有这个问题呀
    volvo007
        22
    volvo007  
       2024-08-22 20:07:55 +08:00
    看看这个有没有帮助 https://www.bilibili.com/video/BV1K24y1k7XA/? spm_id_from=333.999.0.0&vd_source=bcfa969247c2baeec790cdac234b36e6
    marvyn
        23
    marvyn  
       2024-08-24 10:56:28 +08:00
    在对应环境的 site-packages 下新增一个 app.pth ,里面内容就是一行
    比如 D:\xxx_project\app

    导入时:
    from app.models import func
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4000 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 05:17 PVG 13:17 LAX 22:17 JFK 01:17
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86