加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Python_misc<一>Package和module

(2023-08-15 22:06:35)
标签:

python

分类: Python

作者:Sam (甄峰) sam.zhen1977@outlook.com

 

1. Python module(模块):

1.1:module:

Python Module(模块)是一个python文件,以.py结尾。包含了Python对象和Python语句。

模块中能定义函数,class, 变量。 模块中也可以包含可执行的代码。

函数,class,变量可以看成是一块块积木,而一个模块中可以包含多个函数,变量和class,可以看成是一盒积木。

 

 

例如,建立一个python文件:module_sample.py

内容如下:

#!/usr/bin/python3

# -*- coding:utf-8 -*-

 

#这里会显示在 __doc__中

"""

This is module sample document.

"""

 

def print_func(par):

print ("Hello : " , par)

return

 

Money = 25000

def addMoney(val):

global Money

Money = Money + val

 

__all__ = ["addMoney"]

 

print("This is module_sample.py")

 

if __name__ == "__main__":

print(Money)

addMoney(300)

print(Money)

print("This is module_sample program")

print_func(2)

 

想要调用此module内的函数或变量。可以使用import.

import导入module的方式有两种:

A. import module_name1 [as 别名1], module_name2 [as 别名2]

使用这种语法格式的import方式,会导入指定module中所有成员(变量,函数, class). 使用被导入的module中的成员时,需要使用module_name(或者别名)作为前缀。否则Python解释器会报错。

B. from module_name import 成员名1 [as 别名1] 成员名2 [as 成员名2]

使用这种语法格式的import方式,只会导入模块中指定的的成员。需要使用该成员时,无需附加任何前缀,直接使用成员名或者别名即可。这种方式还有个特别方式: from module_name import *   ,可以导入指定module中所有成员。当不推荐使用。(多个module中有同名成员时,会冲突。)

 

1.2: import (方式A):

如果另一个同目录的python程序(test_module.py)想要引入此模块,可以采用import。

 

#!/usr/bin/python3

# -*- coding:utf-8 -*-

 

import module_sample 

#此时调用需要加入模块名

module_sample.print_func("test_module.py")

 

print(module_sample.Money)

module_sample.addMoney(1000)

print(module_sample.Money)

 

#import的本质

print(type(module_sample))

print(module_sample)

 

执行之:

#python test_module.py 

结果:

This is module_sample.py

Hello :  test_module.py

25000

26000

 

 

 

此时,需要调用module中的函数时,需要: 模块名.函数名

 

注意:

A. 不管执行多少次import, 一个模块只被导入一次.

B. 导入模块时,会把模块执行一遍,并生成一个模块对象,类型为 class module。被导入模块中定义的函数,变量,class等会添加到这个模块对象的属性里。 所以我们调用这些函数,变量时,需要通过module调用,因为它就是这个模块对象的属性。

 

 

 

 

1.3: from ... import  (方式B):

这个语句让程序从一个模块中导入指定部分

 

#!/usr/bin/python3

# -*- coding:utf-8 -*-

 

from module_sample import print_func

print_func("import module mode2")

 

结果为:

This is module_sample.py

Hello :  import module mode2

 

注意:

A. 不管执行多少次import, 一个模块只被导入一次.

B. 导入模块时,会把模块执行一遍。同时把指定的函数,变量或class导入到当前命名空间。

 

 

 

1.4:模块的搜索路径:

Python在import module时,有时会出现ModuleNotFoundError: No module named '模块名'。

原因时Python找不到这个模块。 为什么呢,因为Python会遵循一定机制找Python 模块。而咱们要导入的模块不在Python寻找的位置。

 

import或者from .... import时,Python解析器对模块位置的搜索顺序是:

1. 当前目录。

2. shell的 PYTHONPATH目录。

3.  Python 默认的安装目录下查找

 

以上所有涉及到的目录,被保存在sys的sys.path变量中。通过此变量,我们可以看到指定程序查找的所有目录。所以当要导入的模块没有存储在sys.path显示的目录中,那要导入该模块时,就会出现找不到模块的异常。

 

解决方法也很简单。

A. 向sys.path中临时添加模块文件存储位置的路径。

B. 把模块文件放在sys.path变量中已经包含的模块加载路径中。

C. 设置path环境变量。

 

建立一个新python(module_utils.py), 要导入另一个目录内的module( M_Utils/M_Utils_Test1.py).

 

import sys

import module_sample

 

#M_Utils_Test1.py 放在 M_Utils/M_Utils_Test1.py。 所以先把目录加入sys.path

sys.path.append(r"M_Utils")

import M_Utils_Test1

 

 

 

 

print(module_sample.__all__)

 

print(module_sample.__doc__)

 

print(sys.path)

 

 

1.5: module的 __all__, __doc__, __file__:

A. __all__ 变量,该变量的值是一个列表,存储的是当前模块中一些成员(变量、函数或者类)的名称。通过在模块文件中设置 __all__ 变量,当其它文件以“from 模块名 import *”的形式导入该模块时,该文件中只能使用 __all__ 列表中指定的成员。

其它import方式不受__all__影响。

def addMoney(val):

    global Money

    Money = Money + val

 

#

def __showMoney_1():

    print(Money)

 

#只对form modeule_name import * 

#和 显式使用 __all__有效

__all__ = ["addMoney"]

 

print 一个module的 __all__ 可以看到它支持的所有成员(函数,变量和class).

 

B. __file__:

print(module_sample.__file__)

通过调用 __file__ 属性输出的绝对路径,我们可以很轻易地找到该模块(或包)的源文件

 

C. help和__doc__:

虽然通过 __all__. 可以看到模块所有的成员(函数,变量和class), 当并不清楚这些名称代表了什么意思,也不清楚他们的功能。所以就有了  __doc__和 help. 其中,help的底层也是通过 __doc__实现的。

 

help(module_sample)

 

Help on module module_sample:

 

NAME

    module_sample - This is module sample document.

 

FUNCTIONS

    addMoney(val)

 

DATA

    __all__ = ['addMoney']

 

FILE

    f:\work\current\source\svn_sam_2023\linux_tool_utils\trunk\python\python_misc\2_package\module_sample.py

 

注意:

之所以我们可以使用 help() 函数查看具体成员的信息,是因为该成员本身就包含表示自身身份的说明文档(本质是字符串,位于该成员内部开头的位置)。前面讲过,无论是函数还是类,都可以使用 __doc__ 属性获取它们的说明文档,模块也不例外。

 

如果使用 help() 函数或者 __doc__ 属性,仍然无法满足我们的需求,还可以使用以下 2 种方法:

1. 调用 __file__ 属性,查看该模块或者包文件的具体存储位置,直接查看其源代码(后续章节或详细介绍);

2. 对于非自定义的模块或者包,可以查阅 Python 库的参考文档 https://docs.python.org/3/library/index.html

 

 

 

 

 

 

 

 

2. Python Package(包):

2.1:Package:

实际开发中,一个大型项目通常有大量Python模块,如果把模块放在一起,管理起来很困难。 同时,模块虽然可以有效的避免变量名和函数名重名引起的冲突,但如果模块之间重名了怎么办? 于是就有了Package。

 

Package(包)是一个分层次的文件目录结构,它定义了一个由module(模块)及子包和子包下的子包组成的Python的应用环境。

 

 

包是个文件夹,此文件夹必须存在__init__.py文件。 文件内容可以为空, 这个文件的存在用于标识当前文件夹是个Package(也叫常规包,与命名空间包区别).

当一个常规包Package被导入时, 这个__init__.py文件被隐式执行。

 

__init__.py 不同于其他模块文件,此模块的模块名不是 __init__,而是它所在的包名。例如,在 settings 包中的 __init__.py 文件,其模块名就是 settings。

 

 

 

引入Package中的module时,可以:

from package.module import func

 

 

举例如下:

建立目录:P_Utils作为package. 与之同级目录,建立:test_package.py

P_Utils目录内,建立三个文件:__init__.py  P_Utils_1.py  P_Utils_2.py

内容分别为:

__init_.py:

 #!/usr/bin/python3

# -*- coding:utf-8 -*-

 

if __name__ == '__main__':

    print("This is Main program")

else:

    print("Package P_Utils init")

 

P_Utils_1.py :

#!/usr/bin/python3

# -*- coding:utf-8 -*-

 

def utils_1_func():

print ("This is P_Utils_1.py")

return  

 

P_Utils_2.py

#!/usr/bin/python3

# -*- coding:utf-8 -*-

 

def utils_2_func():

print ("This is P_Utils_2.py")

return     

 

 

test_package.py

#!/usr/bin/python3

# -*- coding:utf-8 -*-

 

from P_Utils.P_Utils_1 import utils_1_func

from P_Utils.P_Utils_2 import utils_2_func

 

if __name__ == "__main__":

utils_1_func()

utils_2_func()

 

结果如下:

Package P_Utils init

This is P_Utils_1.py

This is P_Utils_2.py

 

可以看到,要导入package的module。 会先隐式调用__init__.py.

 

2.2 Package包的导入:

包本质上也是模块,所以导入方法和模块的导入有类似:

A. import Package_Name[.Module_name [as 别名]]

B. from Package_Name import Module_Name [as 别名]

C. from Package_Name.Module_Name import 成员名 [as 别名]

 

 

2.2.1: 方法A。 import Package_Name[.Module_name [as 别名]]

 

2.2.1.1:导入包中的模块:

通过此语法格式导入包中的指定模块后,在使用该模块中的成员(变量、函数、类)时,需添加“包名.模块名”为前缀

 

#Blog中方法A

import P_Utils.P_Utils_1

if __name__=="__main__":

    P_Utils.P_Utils_1.utils_1_func()

    print(type(P_Utils.P_Utils_1))

    print(P_Utils.P_Utils_1.__file__)

 

结果:

Package P_Utils init

This is P_Utils_1.py

 

F:\work\current\Source\svn_Sam_2023\Linux_Tool_Utils\trunk\python\Python_Misc\2_Package\P_Utils\P_Utils_1.py

解析:

导入Package中的Module,和直接导入Module一样。会把模块执行一遍,并生成一个模块对象,类型为 class module。被导入模块中定义的函数,变量,class等会添加到这个模块对象的属性里。 所以我们调用这些函数,变量时,需要通过module调用,因为它就是这个模块对象的属性。

 

2.2.1.2:只导入包:

import Package_Name

只导入包名, 程序会自动执行该包下 __init__.py文件中的代码,但并不意味着Package中的其它Module会被import .

 

例如:

import P_Utils

print(type(P_Utils))

print(P_Utils.__file__)

可以看到:

 

F:\work\current\Source\svn_Sam_2023\Linux_Tool_Utils\trunk\python\Python_Misc\2_Package\P_Utils\__init__.py

 

即:只导入包名,它也会建立一个Module. 只是这个Module是 __init__.py

 

2.2.2:方法B:

from Package_Name import Module_Name [as 别名]

 

#Blog中方法B:

from P_Utils import P_Utils_1, P_Utils_2

if __name__=="__main__":

    P_Utils_1.utils_1_func()

    P_Utils_2.utils_2_func()

    print(type(P_Utils_2))

    print(P_Utils_2.__file__)

 

结果:

ackage P_Utils init

This is P_Utils_1.py utils_1_func()

This is P_Utils_2.py utils_2_func

 

F:\work\current\Source\svn_Sam_2023\Linux_Tool_Utils\trunk

 

 

2.2.3:方法C:

from Package_Name.Module_Name import 成员名 [as 别名]

 

#Blog中方法C:

from P_Utils.P_Utils_1 import utils_1_func

if __name__=="__main__":

    print(type(utils_1_func))

    utils_1_func()

 

结果为:

Package P_Utils init

 

This is P_Utils_1.py utils_1_func()

 

 

3. import的机制以及绝对导入和相对导入:

3.1import的运作机制:

当我们使用import 某个Module时,Python会首先在sys.modules中搜索此Module名的模块,如果sys.modules中存在此模块,则将缓存映射的内容直接返回。import流程结束。

如果缓存中没有此模块,Python会依次搜索内置模块列表,sys.path列表定义的路径中搜索该模块。

Python搜索到该模块时,会在本地作用域内初始化相应的module对象,并把模块中的成员以属性的形式赋给module. 这样,就可以使用该模块的各个成员(变量,函数,class)了。

3.2:绝对导入和相对导入:

A. 无论绝对导入还是相对导入,都需要一个参照物。

B. 绝对导入和相对导入是针对包内导入而言的,也就是包内部模块之间的导入。

 

绝对导入的参照物是项目的根文件夹。即使用从项目的根文件夹到要导入的模块的完整路径。

 

 

4. Script(脚本):

一个Python文件,要么是个脚本(Script),要么是个模块(module), 这取决于此Python文件的使用方式。

若直接运行Python文件,则称之为运行一个python script.

若在另一个Python文件中import这个文件或文件中的对象,函数或class. 则此Python文件称之为module.

 

这里也解释下常见的一个python参数。

-m mod run library module as a script (terminates option list)

“-m”选项后面的内容是 module(模块),其作用是把模块当成脚本来运行。

 

“terminates option list”意味着“-m”之后的其它选项不起作用,在这点上它跟“-c”是一样的,都是“终极选项”。

 

Python解释器会查找名为name的module或者package。并将其内容当做 “__main__”来执行。

 

 

 

 

 

1:

She-bang(#!):用来在Linux/unit系统中指定程序程序的,又叫hashbang. 就是一个 #!.

 

shebang符号通常在Linux/Unix系统的脚本中第一行的开头写,它指明了执行这个脚本文件的解释程序。(解释程序必须使用绝对路径)

 

A. 如果脚本中没有#!这一行,则执行时会默认使用当前shell去解释这个脚本。

 

B. 如果脚本中 #!

指定的解释程序是一个可执行文件,则执行这个脚本时,会把这个文件名和参数一起作为参数传递给解释程序去执行。

 

C. 如果 #!指定的解释程序没有执行权限,则报错 无权限。

 

D. 如果#!指定的解释程序不是一个可执行程序,则会被忽略,转而调用SHELL去解释。

 

E. 

如果#!指定的解释程序不存在。则会报错。

 

 

 

Python程序为例,如果没有 shebang. 则必须显式的指定解释程序:

 

# python

she_bang.py

如果添加了shebang,并修改she_bang.py为可执行权限。

 

#!/usr/bin/python3

print("This is

she_bang test program.")

则可以直接执行:

 

#./she_bang.py

 

 

Windows下,系统利用后缀名判断文件类型,所以.py程序会自动关联到python程序去执行,she_bang不起任何作用。只被视为普通注释。

 

 

 

2:

# -*- coding:utf-8 -*-

Python

2.x版本的py文件一般默认的是ASCII码,如果文件里有中文,运行时会出现乱码,注释是中文也不行。因此,需要把文件编码类型改为utf-8的类型,输入#

-*- coding:utf-8 -*-之后会把文件编码强制转换为utf-8。 Python

3.x版本的py文件的默认编码为Unicode,也就是说不用进行编码声明,可以直接使用中文了。

 

0

阅读 收藏 喜欢 打印举报/Report
前一篇:Docker
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有