• 第10章 模块和包


    简介

    • 包:将 多个功能模块 放在 一个包含__init__.py的文件夹里 , 对 不同功能的模块 进行分组管理。包可以嵌套定义。
    • 模块:一个封装 具有相似功能的多个函数 的Python文件。

    (在PyCharm中,创建普通文件夹并在其中创建__init__.py,普通文件夹将自动转换标记为package,和直接创建package结果相同)

    导入

    # from和import之后...代表 包名/模块名/属性名/方法名/类名
    # as之后...代表 别名
    import ...
    import ... as ...
    from ... import ...
    from ... import ... as ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    导入包后,python解释器会找到包并执行其中的部分代码。在sys.path中可以看到python解释器会查找的路径。若导入包后提示没有找到包或包不存在,可以执行其中一个操作:1)将包放在正确的位置;2)告诉解释器到哪里去找包;

    方便理解,这里举一个例子:
    phello: 包
    __init__.py 创建包时的默认文件
    mhello.py 模块

    # mhello.py
    def printHello():
        print('Hello World!')
    
    • 1
    • 2
    • 3

    1)将包放在正确的位置

    sys.path包含一个目录列表,解释器将在这些目录中查找包。

    其中较常用的为“site-packages目录”和“当前项目目录”。其中site-packages为默认的包安装位置,pip install和conda install的包都将存放在site-packages目录下;当前项目目录指的是用户个人正在编写的项目位置,在PyCharm中创建的包一般放在当前项目目录(或更下级目录)中,简单直观,方便编写和调试。

    site-packages目录:不要放置单个py文件(例如mhello.py),而是放置包含py文件的包/文件夹(例如phello)
    当前项目目录:可以放置单个py文件(例如mhello.py)

    # 打印sys.path内容查看搜索路径
    
    # windows
    >>> import sys
    >>> print(sys.path)
    ['E:\\PyCharm 2021.3\\plugins\\python\\helpers\\pydev', 
    'E:\\PyCharm 2021.3\\plugins\\python\\helpers\\pycharm_display',
    'E:\\PyCharm 2021.3\\plugins\\python\\helpers\\third_party\\thriftpy', 
    'E:\\PyCharm 2021.3\\plugins\\python\\helpers\\pydev', 
    'E:\\anaconda\\envs\\py37tfcpu\\python37.zip', 
    'E:\\anaconda\\envs\\py37tfcpu\\DLLs', 
    'E:\\anaconda\\envs\\py37tfcpu\\lib',
    'E:\\anaconda\\envs\\py37tfcpu', 
     # site-packages目录
    'E:\\anaconda\\envs\\py37tfcpu\\lib\\site-packages',
    'E:\\PyCharm 2021.3\\plugins\\python\\helpers\\pycharm_matplotlib_backend',
     # 当前项目目录
    'C:\\Users\\shang\\Desktop\\pythonProject', 
    'C:/Users/shang/Desktop/pythonProject']
    
    # linux
    >>> import sys
    >>> print(sys.path)
    [
    # 当前项目目录
    '', 
    '/root/miniconda3/envs/moviedeal/lib/python37.zip',
    '/root/miniconda3/envs/moviedeal/lib/python3.7',
    '/root/miniconda3/envs/moviedeal/lib/python3.7/lib-dynload',
     # site-packages目录
    '/root/miniconda3/envs/moviedeal/lib/python3.7/site-packages']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    windows例:

    # 将phello包放到main.py同级目录
    
    # main.py
    from phello.mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    # 将mhello.py模块放到main.py同级目录
    
    # main.py
    from mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    # 将phello包放到'E:\\anaconda\\envs\\py37tfcpu\\lib\\site-packages'目录中
    
    # main.py
    from phello.mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    linux例:

    # 将phello包放到main.py同级目录
    
    # main.py
    from phello.mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    # 将mhello.py模块放到main.py同级目录
    
    # main.py
    from mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    # 将phello包放到'/root/miniconda3/envs/moviedeal/lib/python3.7/site-packages'目录中
    
    # main.py
    from phello.mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2)告诉解释器到哪里去找

    i)直接修改sys.path(不常见)

    仅修改运行此次运行的sys.path

    windows

    # 将phello包放到main.py同级目录放在D盘根目录则sys.path.append('D:')
    # 将phello包放到main.py同级目录放在D:/pkg录则sys.path.append('D:/pkg')
    
    # main.py
    import sys
    sys.path.append('D:/pkg')
    
    from phello.mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    linux

    将phello包放到’~'目录下

    不能直接将’‘添加到sys.path的末尾,必须使用完整的路径(例如’/home/yourusername’)或自动创建完整的路径(os.path.expanduser(''))

    # main.py
    import sys
    sys.path.append('/home/yourusername')
    
    from phello.mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    # main.py
    import sys
    import os
    sys.path.append(os.path.expanduser('~'))
    
    from phello.mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ii)添加环境变量(标准做法

    关于环境变量详细参考:windows和linux的环境变量

    pycharm会占用PYTHONPATH变量,使得在系统中配置的PYTHONPATH失效,所以分为使用cmd和使用pycharm运行main.py

    windows

    将phello包放到’D:\pkg’目录下

    使用cmd

    添加环境变量

    image-20220803223856461

    # main.py
    from phello.mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4
    使用pycharm

    在pycharm的解释器上添加临时环境变量

    image-20220803225031665

    image-20220803225106748

    # main.py
    from phello.mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4

    linux

    将phello包放到’~'目录下

    使用cmd
    > vim ~/.bashrc
    # 在后面插入一行
    # export PYTHONPATH=$PYTHONPATH:~
    > source ~/.bashrc
    
    • 1
    • 2
    • 3
    • 4
    # 命令行执行,不要使用pycharm(pycharm会占用PYTHONPATH变量,使得在系统中配置的PYTHONPATH失效)
    
    # main.py
    from phello.mhello import printHello
    
    printHello()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    使用pycharm

    同windows,在pycharm的解释器上添加临时环境变量

    编写

    模块

    注意__all__的使用:__all__为 from … import * 后外部所能导入属性,方法、类等,直接使用"模块名.xxx"或导入时指定"属性,方法,类"则不受影响。即__all__内容为该模块的主观开放成员(属性、方法、类等),所谓主观开放即作者主观上允许其他人调用的,而不在__all__中的内容作者不希望其他人调用(但是python语言的机制不是强制的,直接使用"模块名.xxx"或导入时指定"属性,方法,类"仍然可以调用)。

    1. 新建py文件test.py
    2. 编写模块
    # test.py
    __all__=['t1', 'printHello']
    
    t1 = 2
    
    t2 = 3
    
    
    def printHello():
        print('Hello')
    
    
    def printWorld():
        print('world')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1. 导入和调用测试
    # 成功调用t1, t2, printHello, printWorld
    import test
    print(test.t1)
    print(test.t2)
    test.printHello()
    test.printWorld()
    # 2
    # 3
    # Hello
    # world
    
    # 成功调用t1, t2, printHello, printWorld
    from test import t1, t2, printHello, printWorld
    print(t1)
    print(t2)
    printHello()
    printWorld()
    # 2
    # 3
    # Hello
    # world
    
    # 成功调用t1, printHello
    # t2, printWorld不存在
    from test import *
    print(t1)
    printHello()
    # 2
    # Hello
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    # digithello.py
    
    __all__ = ['hello1', 'hello2']
    
    
    def hello1():
        print('Hello 1')
    
    
    def hello2():
        print('Hello 2')
    
    
    def selfhello3():
        print('Self Hello 3')
        
        
    # letterhello.py
    
    __all__ = ['helloA', 'helloB']
    
    
    def helloA():
        print('Hello A')
    
    
    def helloB():
        print('Hello B')
    
    
    def selfhelloC():
        print('Self Hello C')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    空init

    # __init__.py为空
    
    
    # main.py
    
    from hello.digithello import *
    from hello.letterhello import *
    
    hello1()
    hello2()
    helloA()
    helloB()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    非空init

    使用__init__.py的优点:
    1) 在__init__.py按需批量import,可以简化调用该包时的import语句
    2) 在__init__.py按需import 搭配 新的__all__,定义 综合包内各个模块的总主观开放成员

    # __init__.py
    
    # 模块名可以使用hello.xxx或.xxx,不能使用xxx
    from hello.digithello import *
    from hello.letterhello import selfhelloC
    
    __all__ = []
    # 此处只能使用xxx.__all__,不能使用.xxx.__all__或hello.xxx.__all__
    __all__.extend(digithello.__all__)
    __all__.append('selfhelloC')
    
    
    # main.py
    from hello import *
    
    hello1()
    hello2()
    selfhelloC()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    __,定义 综合包内各个模块的总主观开放**成员

    # __init__.py
    
    # 模块名可以使用hello.xxx或.xxx,不能使用xxx
    from hello.digithello import *
    from hello.letterhello import selfhelloC
    
    __all__ = []
    # 此处只能使用xxx.__all__,不能使用.xxx.__all__或hello.xxx.__all__
    __all__.extend(digithello.__all__)
    __all__.append('selfhelloC')
    
    
    # main.py
    from hello import *
    
    hello1()
    hello2()
    selfhelloC()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    提交Spark作业遇到的NoSuchMethodError问题
    RabbitMQ消息丢失的场景,如何保证消息不丢失?(详细讲解,一文看懂)
    49、C++/友元、常成员函数和常对象、运算符重载学习20240314
    Can‘t connect to MySQL server on ‘localhost3306‘ (10061) 简洁明了的解决方法
    Java框架(四)--Spring AOP面向切面编程(2)--五种通知类型及利用注解配置Spring AOP
    数据挖掘与分析课程笔记(Chapter 20)
    学习ASP.NET Core Blazor编程系列十——路由(上)
    新加坡大带宽服务器托管优势
    【QT教程】QT6物联网应用
    任意文件上传
  • 原文地址:https://blog.csdn.net/qq_42283621/article/details/126151054