Python基础学习笔记之——模块

模块

1、模块

1.1、模块就是程序

任何 Python 程序都可以作为模块导入。假设你写了一个 hello.py 文件,这个文件名称将成为模块的名称。

print("hello world!")

文件的存储位置也很重要,要告诉解释器去哪里找这个模块,可执行如下命令

>>> import sys
>>> sys.path.append(/usr/local/src/python/)

这样做之后,就告诉解释器,除了通常查找的位置外,还应到目录 E:\practice\python\first\Python基础教程中查找这个模块。之后,就可以导入模块了;

>>> import hello
Hello World!

当你导入模块时,可能发现其所在的目录中除了源代码文件外,还新建了一个名为 _pycahce_ 的子目录。这个目录包含处理后的文件,Python 能够高效地处理他们。以后再导入这个模块时,如果 .py 文件未发生变化,Python 将导入处理后的文件,否则将重新生成处理后的文件。

[root@li python]# ll
总用量 24
-rw-r--r--. 1 root root  22 8月   3 18:41 hello.py
drwxr-xr-x. 2 root root  34 8月   3 18:43 __pycache__

1.2、模块是用来下定义的

让模块值得被创建的原因在于他们像类一样,有自己的作用域。这意味着在模块中定义的类和函数以及对其进行赋值的变量都将成为模块的属性。

1.2.1、在模块中定义函数

假设编写了一个类似于下面代码的模块,并将其存储在文件 hello2.py 中:

[root@li python]# vim hello2.py
def hello():
        print("Hello World!")

可以像下面这样访问 hello() 函数:

>>> import hello2	#这将执行这个模块,也就是在这个模块的作用域内定义函数 hello()
>>> hello2.hello()
Hello World!

在模块的全局作用域中定义的名称都可像上面这样访问。那为什么不在主程序中定义一切呢?主要是为了重用代码

1.2.2、在模块中添加测试代码

模块用于定义函数和类等,但在大部分情况下,需要添加一些测试代码来检查情况是否符合预期。例如:如果要确定函数 hello 是否管用,你可将模块 hello2 重写为如下代码:

[root@li python]# vim hello3.py
def hello():
        print("Hello World!")

#一个测试
hello()
>>> import hello3
Hello World!
>>> hello3.hello()
Hello World!

但这并不是你想要的,要避免这种情况,关键是检查模块是作为程序运行还是被导入另一个程序。为此,使用变量_name_:

>>> __name__
'__main__'
>>> hello3.__name__
'hello3'

因此,可以进一步修改为:

[root@li python]# vim hello4.py
def hello():
        print("Hello World!")

#一个测试
def test():
        hello()

if __name__ == '__main__':test()

如果将这个模块作为程序运行,将执行函数 hello;如果导入它,其行为将像普通模块一样:

>>> import hello4
>>> hello4.hello()
Hello World!

测试时可以使用:

>>> hello4.test()
Hello World!
1.2.3、让模块可用

在上面我们修改了 sys.path。sys.path 包含了一个目录列表,解释器将在这些目录中查找模块。但通常你并不希望这样做。最理想的情况是,sys.path 一开始就包含正确的目录。为此有两个办法:1、将模块放在正确的位置;2、告诉解释器到哪里去查找

1.2.3.1、将模块放在正确的位置

将模块放在正确的位置很容易,只需要找出 Python 解释器到哪里去找,再将文件放在呢个地方即可。

>>> import sys,pprint		#如果打印的数据结构太大,可使用模块 pprint 中的函数 pprint
>>> pprint.pprint(sys.path)
['',
 '/usr/lib64/python36.zip',
 '/usr/lib64/python3.6',
 '/usr/lib64/python3.6/lib-dynload',
 '/usr/lib64/python3.6/site-packages',
 '/usr/lib/python3.6/site-packages']

其中目录 site-packages 是最佳的选择,因为它就是用来放置模块的。

[root@li python]# cd /usr/lib64/python3.6/site-packages
[root@li site-packages]# vim another_hello.py
def hello():
        print("Hello World!")

#一个测试
def test():
        hello()

if __name__ == '__main__':test()
>>> import another_hello
>>> another_hello.hello()
Hello World!
1.2.3.2、告诉解释器到哪里去找

将模块放在正确的位置可能不是合适的解决方案,其中原因很多:

  • 不希望 Python 解释器的目录中充斥着你编写的代码;
  • 没有必要的权限,无法将文件保存到 Python 解释器的目录中;
  • 想将模块放在其他地方。

最重要的是,如果想将模块放在其他地方,就告诉解释器到哪里去找。方法之一就是修改 sys.path,但这种方法不常见。标准做法是将模块所在的目录包含在环境变量 PYTHONPATH 中

[root@li site-packages]# export PYTHONPATH=$PYTHONPATH:/usr/local/src/python/

​ 除了使用环境变量之外,还可以使用路径配置文件。这些文件的扩展名为 .pth

1.2.4、包

为了组织模块,可将其编组为包(package)。包其实就是另一种模块,但它可以包含其他模块。要被 Pythton 视为包,目录必须包含文件 _init_.py。例如,如果有一个名为 contents 的包,而文件 contants/_init_.py 包含语句 PI=3.14,可想如下定义:

[root@li site-packages]# cd /usr/local/src/python/
[root@li python]# mkdir contents
[root@li python]# cd contents/
[root@li contents]# ls
[root@li contents]# vim __init__.py
PI = 3.14
>>> import contents
>>> print(contents.PI)
3.14

要将模块加入包中,只需要模块文件放在包目录中即可。还可以在包中嵌套其他包。例如:要创建一个名为 drawing 的包,其中包含模块 shapes 和 colors,需要创建如下的文件和目录:

文件/目录描述
~/python/PYTHONPATH中的目录
~/python/drawing/包目录(包 drawing)
~/python/drawing/_init_.py包代码(模块 drawing)
~/python/drawing/colors.py模块 colors
~/python/drawing/shapes.py模块 shapes

完成这些工作后。下面语句都是合法的:

>>> import drawing

执行完这条语句后,便可以使用目录 drawing 中文件 _init_.py 的内容,但不能使用模块 shapes 和 colors 的内容。

>>> import drawing.colors

可使用模块 colors,但只能通过全限定名使用 drawing.colors。

>>> from drawing import shapes

可使用简化名(shapes)来使用模块 shapes。


2、探索模块

2.1、模块包含什么

以 copy 模块为例:

>>> import copy
2.1.1、使用 dir

要查明模块包含哪些东西,可使用函数 dir,它列出对象的所有属性(对于模块,它列出所有的函数、类、变量等)。如果将 dir(copy) 打印出来,将是很长的名称列表:

>>> print(dir(copy))
['Error', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_copy_dispatch', '_copy_immutable', '_deepcopy_atomic', '_deepcopy_dict', '_deepcopy_dispatch', '_deepcopy_list', '_deepcopy_method', '_deepcopy_tuple', '_keep_alive', '_reconstruct', 'copy', 'deepcopy', 'dispatch_table', 'error']

其中,以下划线打头的并非供外部使用的,因此,我们将它过滤掉:

>>> [n for n in dir(copy) if not n.startswith('_')]
['Error', 'copy', 'deepcopy', 'dispatch_table', 'error']
2.1.2、变量_all_

在完整清单中,包含_all_。这个变量包含一个列表,它与前面使用列表推导出来的列表类似,但是在模块内部设置的

>>> copy.__all__
['Error', 'copy', 'deepcopy']	#上面的推导多了几个并非供用户使用的模块

这个__all__是怎么来的呢?为什么要提供它?第一个问题很容易回答:可以像下面这样设置:

>>> __all__ = ['Error', 'copy', 'deepcopy']

至于为什么要提供它?旨在定义模块的公有接口。具体的说,它告诉解释器从这个模块导入所有的名称意味着什么?例如:

>>> from copy import *

将只能得到变量__all__中列出的 3 个函数。要导入 dispatch_table,必须显式声明:导入 copy 并使用 copy.dispatch_table;或者使用 from copy import dispatch_table。

如果不设置_all_,则会在以 import * 方式导入时,导入所有不以下划线打头的全局名称。

2.2、使用 help 获取帮助

>>> help(copy)
Help on function copy in module copy:

copy(x)
    Shallow copy operation on arbitrary Python objects.

    See the module's __doc__ string for more info.

2.3、使用文档

>>> print(range.__doc__)
range(stop) -> range object
range(start, stop[, step]) -> range object

Return an object that produces a sequence of integers from start (inclusive)
to stop (exclusive) by step.  range(i, j) produces i, i+1, i+2, ..., j-1.
start defaults to 0, and stop is omitted!  range(4) produces 0, 1, 2, 3.
These are exactly the valid indices for a list of 4 elements.
When step is given, it specifies the increment (or decrement).

2.4、使用源代码

>>> import copy
>>> print(copy.__file__)
/usr/lib64/python3.6/copy.py
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值