Python学习笔记:模块和包

时间:2021-08-19
本文章向大家介绍Python学习笔记:模块和包,主要包括Python学习笔记:模块和包使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

第九章 模块和包

模块化编程

导入模块的语法

使用import导入模块,主要有两种用法:

  • import 模块名1[as 别名1],模块名2[as 别名2],... : 导入整个模块
  • from 模块名 import 成员名1[as 别名1], 成员名2[as 别名2],...,:导入模块中指定成员

上面两种import语句的区别主要有两点:

  • 第一种import语句导入模块内的所有成员(包括变量、函数、类等);第二种import语句只导入模块内的指定成员(除非使用 from 模块名 import *)
  • 当使用第一种import语句导入模块中的成员时,必须添加模块名或模块别名作为前缀;当使用第二种import语句导入模块中的成员时,无须使用任何前缀,直接使用成员名或成员别名即可


使用import导入模块介绍

# 导入sys整个模块
import sys
# 使用sys模块名作为前缀来访问模块中的成员
print(sys.argv[0])

输出结果:
C:\Users\zz\.spyder-py3\temp.py

为模块指定别名,示例:

# 导入sys整个模块,并指定别名为s
import sys as s
# 使用s模块别名作为前缀来访问模块中的成员
print(s.argv[0])

当指定了别名,就必须使用别名作为前缀,如果仍旧使用模块名,则会报错:

# 导入sys整个模块,并指定别名为s
import sys as s
# 使用s模块别名作为前缀来访问模块中的成员
print(s.argv[0])

print("------------")
# 仍旧使用模块名作为前缀,则会报错
print(sys.argv[0])

输出结果:
C:\Users\zz\.spyder-py3\temp.py
------------
Traceback (most recent call last):

  File "C:\Users\zz\.spyder-py3\temp.py", line 8, in <module>
    print(sys.argv[0])

NameError: name 'sys' is not defined

一次导入多个模块,多个模块之间用逗号隔开,示例:

# 导入sys、os两个模块
import sys,os
# 使用模块名作为前缀来访问模块中的成员
print(sys.argv[0])
# os模块的sep变量代表平台上的路径分隔符
print(os.sep)


输出结果:
C:\Users\zz\.spyder-py3\temp.py
\

为多个模块指定别名,示例:

# 导入sys、os两个模块,并为sys指定别名s,为os指定别名o
import sys as s,os as o
# 使用模块别名作为前缀来访问模块中的成员
print(s.argv[0])
print(o.sep)

使用from ... import 导入模块内指定成员的用法介绍

# 导入sys模块的argv成员
from sys import argv
# 使用导入成员的语法,直接使用成员名访问,不能添加前缀
print(argv[0])

如果为成员名添加模块名前缀,则会报错,示例:

# 导入sys模块的argv成员
from sys import argv
# 使用导入成员的语法,直接使用成员名访问
print(argv[0])

print("--------------------")

# 如果为成员名添加模块名前缀,则会报错
print(sys.argv[0])

输出结果:
C:\Users\zz\.spyder-py3\temp.py
--------------------
Traceback (most recent call last):

  File "C:\Users\zz\.spyder-py3\temp.py", line 9, in <module>
    print(sys.argv[0])

NameError: name 'sys' is not defined

为成员名指定别名,示例:

# 导入sys模块的argv成员,并为其指定别名v
from sys import argv as v
# 使用导入成员(并指定别名)的语法,直接使用成员的别名访问
print(v[0])

# 如果指定了别名,就必须使用别名,若仍使用成员名,则会报错
print(argv[0])

输出结果:
C:\Users\zz\.spyder-py3\temp.py
Traceback (most recent call last):

  File "C:\Users\zz\.spyder-py3\temp.py", line 7, in <module>
    print(argv[0])

NameError: name 'argv' is not defined

导入多个模块,示例:

# 导入sys模块的argv,winver成员
from sys import argv, winver
# 使用导入成员的语法,直接使用成员名访问
print(argv[0])
print(winver)

为多个模块指定别名,示例:

# 导入sys模块的argv,winver成员,并为其指定别名v、wv
from sys import argv as v, winver as wv
# 使用导入成员(并指定别名)的语法,直接使用成员的别名访问
print(v[0])
print(wv)

输出结果:
C:\Users\zz\.spyder-py3\temp.py
3.7

小结:

  • 一旦为模块名或成员名指定了别名,则在程序中必须使用别名,若仍旧使用模块名作为前缀则会报错、若仍旧使用成员名也会报错
  • 使用成员名访问时,不能添加模块名作为前缀,若强制添加模块名作为前缀则会报错

使用from ... import语法时也可一次导入指定模块内的所有成员,程序即可使用成员名来使用该模块内的所有成员。(不推荐使用这种语法)示例:

# 导入sys模块的所有成员
from sys import *
# 使用导入成员的语法,直接使用成员的别名访问
print(argv[0])
print(winver)

输出结果:
C:\Users\zz\.spyder-py3\temp.py
3.7

定义模块

模块到底是什么?模块就是python程序,任何python程序都可作为模块导入。对于任何程序,只要导入了模块,即可使用该模块内的所有成员。
module1.py代码:

'''
这是我们编写的第一个模块,该模块包含以下内容:
my_book:字符串变量
say_hi:简单的函数
User:代表用户的类
'''
print('这是module 1')
my_book = '疯狂Python讲义'
def say_hi(user):
    print('%s,您好,欢迎学习Python' % user)
class User:
    def __init__(self, name):
        self.name = name
    def walk(self):
        print('%s正在慢慢地走路' % self.name)
    def __repr__(self):
        return 'User[name=%s]' % self.name

使用模块的好处在于:如果将程序需要使用的程序单元(比如modulel.py定义的say_hi()函数、User类)定义在模块中,后面不管哪个程序,只要导入该模块,该程序即可使用该模块所包含的程序单元,这样就可以提供很好的复用一一导入模块,使用模块,从而避免每个程序都需要重新定义这些程序单元。
模块文件的文件名就是它的模块名,比如module1.py的模块名就是module1。

为模块编写说明文档

在实际开发中也应该为模块编写说明文档,否则,其他开发者都不知道该模块有什么作用,以及包含哪些功能
为模块编写说明文档很简单,只要在模块开始处定义一个字符串直接量即可,可通过模块的__doc__属性访问文档。module1.py的第一行代码之前添加如下内容,这段内容将作为该模块的说明文档。

'''
这是我们编写的第一个模块,该模块包含以下内容:
my_book:字符串变量
say_hi:简单的函数
User:代表用户的类
'''

为模块编写测试代码

当模块编写完成之后,可能还需要为模块编写一些测试代码,用于测试模块中的每一个测试单元是否都能正常运行。
希望实现的效果:如果直接使用python命令运行该模块(相当于测试),程序应该执行该模块的测试函数;如果是其他程序导入该模块,程序不应该执行该模块的测试函数。此时可借助于所有模块内置的__name__变量进行区分,如果直接使用Python命令来运行一个模块,name__变量的值为__main;如果该模块导入被导入其他程序中,__name__变量的值就是模块名。因此,如果希望测试函数只有在使用python命令直接运行时才执行,则可在调用测试函数
时增加判断:只有当__name__属性为__main__时才调用测试函数。为模块增加如下代码即可

'''
这是我们编写的第一个模块,该模块包含以下内容:
my_book:字符串变量
say_hi:简单的函数
User:代表用户的类
'''
print('这是module 1')
my_book = '疯狂Python讲义'
def say_hi(user):
    print('%s,您好,欢迎学习Python' % user)
class User:
    def __init__(self, name):
        self.name = name
    def walk(self):
        print('%s正在慢慢地走路' % self.name)
    def __repr__(self):
        return 'User[name=%s]' % self.name
          
        
# ===以下部分是测试代码===
def test_my_book ():
    print(my_book)
def test_say_hi():
    say_hi('孙悟空')
    say_hi(User('Charlie'))
def test_User():
    u = User('白骨精')
    u.walk()
    print(u)
# 当__name__为'__main__'(直接使用python运行该模块)时执行如下代码
if __name__ == '__main__':
    test_my_book()
    test_say_hi()
    test_User()

使用python module1.py命令来运行该模块,输出结果:

这是module 1
疯狂Python讲义
孙悟空,您好,欢迎学习Python
User[name=Charlie],您好,欢迎学习Python
白骨精正在慢慢地走路
User[name=白骨精]

加载模块

在编译一个python模块之后,如果直接用import或from ... import来导入该模块,python通常并不能加载该模块。道理很简单:python怎么知道到哪里去找这个模块呢?
为了让python能找到我们编写(或第三方提供)的模块,可以使用两种方式来告诉它:

  • 使用环境变量
  • 将模块放在默认的模块加载路径之下

使用环境变量

Python将会根据PYTHONPATH环境变量的值来确定到哪里去加载模块。PYTHONPATH环境变量的值是多个路径的集合,这样Python就会依次搜索PYTHONPATH环境变量所指定的多个路径,试图从中找到程序想要加载的模块。


在windows平台上设置环境变量
一般建议设置“用户变量”即可,因为用户变量只对当前用户有效,而系统变量对所有用户有效。为了减少自己所做的修改对其他人的影响,故设置用户变量。对于当前用户而言,设置用户变量和系统变量的效果大致相同,不过系统变量的路径排在用户变量的路径之前。
在“变量名”文本框内输入PYTHONPATH,表明将要建立名为PYTHONPATH的环境变量:在“变量值”文本框内输入 .;d:\python_module,这就是该环境变量的值,该值其实包含了两条路径(分号为分隔符),第一条路径为一个点(.),这个点代表当前路径,表明当运行Python程序时,Python总能从当前路径加载模块:第二条路径为d:\python_module,表明当运行Python程序时,Python总能从d:\python_module加载模块。
在成功设置了上面的环境变量之后,接下来只要把前面定义的模块(Python程序)放在与当前所运行Python程序相同的路径中(或放在d:\python_module路径下),该模块就能被成功加载了。
提示:设置完环境变量后,需要重启 spyder 编辑器,让spyder重新加载环境变量的值。

# 导入module1,并指定其别名为md
import module1 as md
print(md.my_book)
md.say_hi('Charlie')
user = md.User('孙悟空')
print(user)
user.walk()

输出结果:
这是module 1
疯狂Python讲义
Charlie,您好,欢迎学习Python
User[name=孙悟空]
孙悟空正在慢慢地走路

默认的模块加载路径

python默认的模块加载路径由sys.path变量代表,可通过在交互式解释器中输入如下命令来查看:

import sys,pprint

pprint.pprint(sys.path)
['C:\\Users\\zz',
 'D:\\Python\\python_module',
 'D:\\6.CommonTools\\anaconda2\\envs\\python37\\python37.zip',
 'D:\\6.CommonTools\\anaconda2\\envs\\python37\\DLLs',
 'D:\\6.CommonTools\\anaconda2\\envs\\python37\\lib',
 'D:\\6.CommonTools\\anaconda2\\envs\\python37',
 '',
 'D:\\6.CommonTools\\anaconda2\\envs\\python37\\lib\\site-packages',
 'D:\\6.CommonTools\\anaconda2\\envs\\python37\\lib\\site-packages\\win32',
 'D:\\6.CommonTools\\anaconda2\\envs\\python37\\lib\\site-packages\\win32\\lib',
 'D:\\6.CommonTools\\anaconda2\\envs\\python37\\lib\\site-packages\\Pythonwin',
 'D:\\6.CommonTools\\anaconda2\\envs\\python37\\lib\\site-packages\\IPython\\extensions',
 'C:\\Users\\zz\\.ipython']

如果要打印的内容很多,使用pprint可以显示更友好的打印结果。
通常来说,我们应该将python的扩展模块添加在 lib\site-packages 路径下,它专门用于存放python的扩展模块和包。
下面编写一个python模块文件(print_shape.py),并将该文件复制到 lib\site-packages\ 目录下面,就相当于为python扩展了一个 print_shape 模块,这样任何python程序都可使用该模块,示例:

# coding: utf-8
'''
简单的模块,该模块包含以下内容
my_list:保存列表的变量
print_triangle: 使用星号打印三角形的函数
'''
my_list = ['Python', 'Kotlin', 'Swift']
def print_triangle(n):
    '''使用星号打印一个三角形'''
    if n <= 0:
        raise ValueError('n必须大于0')
    for i in range(n):
        print(' ' * (n - i - 1), end='')
        print('*' * (2 * i + 1), end='')
        print('')

# ====以下是测试代码====
def test_print_triangle():
    print_triangle(3)
    print_triangle(4)
    print_triangle(7)
if __name__ == '__main__': test_print_triangle()

交互式解释器中测试该模块:

(base) C:\Users\zz>conda activate python37

(python37) C:\Users\zz>python
Python 3.7.9 (default, Aug 31 2020, 17:10:11) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import print_shape
>>> print(print_shape.__doc__)

简单的模块,该模块包含以下内容
my_list:保存列表的变量
print_triangle: 使用星号打印三角形的函数

>>> print_shape.print_triangle.__doc__
'使用星号打印一个三角形'
>>> print_shape.my_list[1]
'Kotlin'
>>> print_shape.print_triangle(5)
    *
   ***
  *****
 *******
*********
>>> 

从上面可以看到,程序通过模块名前缀访问my_list变量,输出了该变量的第二个元素。

导入模块的本质

定义一个新的模块(fk_module.py),该模块比较简单,示例:

'一个简单的测试模块: fkmodule'
print("this is fk_module")
name = 'fkit'

def hello():
    print("Hello, Python")

接下来,在相同路径下定义如下程序来使用该模块,示例:

import fk_module

print("================")
# 打印fk_module的类型
print(type(fk_module))
print(fk_module)
print(fk_module.name)
print(fk_module.hello)

输出结果:

this is fk_module
================
<class 'module'>
<module 'fk_module' from 'C:\\Users\\zz\\.spyder-py3\\fk_module.py'>
fkit
<function hello at 0x000001577127FC18>

使用“import fk_module”导入模块的本质就是:将fk_module.py中的全部代码加载到内存井执行,然后将整个模块内容赋值给与模块同名的变量(fk_module),该变量的类型是module,而在该模块中定义的所有程序单元都相当于该module对象的成员。


再试试使用from ... import 语句来执行导入,示例:

from fk_module import name, hello

print("================")
print(name)
print(hello)
# 打印fk_module
print(fk_module)

输出结果:

this is fk_module
================
fkit
<function hello at 0x00000157712CE678>
Traceback (most recent call last):

  File "C:\Users\zz\.spyder-py3\temp.py", line 7, in <module>
    print(fk_module)

NameError: name 'fk_module' is not defined

使用 "from fk_module import name, hello" 导入模块中成员的本质是:将fk_module.py中的全部代码加载到内存并执行,然后只导入指定变量、函数等成员单元,并不会将整个模块导入,因此上面程序在输出fk_module时将看到错误提示:name 'fk_module' is not defined


在导入模块后,可以在模块文件所在目录下看到一个名为"pycache"的文件夹,打开该文件夹,可以看到Python为每个模块都生成一个*.cpython-36.pyc文件,比如Python为fk_module模块生成一个fk_module.cpython-36.pyc文件,该文件其实是Python为模块编译生成的字节码,用于提升该模块的运行效率。

模块的__all__变量

在默认情况下,如果使用“from 模块名 import *”这样的语句来导入模块,程序会导入该模块中所有不以下画线开头的程序单元,这是很容易想到的结果。
有时候模块中虽然包含很多成员,但并不希望每个成员都被暴露出来供外界使用,此时可借助于模块的__all__变量,将变量的值设置成一个列表,只有该列表中的程序单元才会被暴露出来。
定义一个包含__all__变量的模块(all_module.py)

'测试__all__变量的模块'

def hello():
    print("Hello, Python")
def world():
    print("Pyhton World is funny")
def test():
    print('--test--')

# 定义__all__变量,指定默认只导入hello和world两个程序单元
__all__ = ['hello', 'world']

示范模块中__all__变量的用处

# 导入all_module模块内所有成员
from all_module import *
hello()
world()
test() # 会提示找不到test()函数

输出结果:
Hello, Python
Pyhton World is funny
Traceback (most recent call last):

  File "C:\Users\zz\.spyder-py3\temp.py", line 5, in <module>
    test() # 会提示找不到test()函数

NameError: name 'test' is not defined

上面程序显示,只导入了__all__变量所列的程序单元,函数test()默认没有被导入。


__all__变量的意义在于为模块定义了一个开放的公共接口。通常来说,只有__all__变量列出的程序单元,才是希望该模块被外界使用的程序单元。因此,为模块设置__all__变量还是比较有用的。比如一个实际的大模块可能包含了大量其他程序不需要使用的变量、函数和类,那么通过__all__变量即可把它们自动过滤掉,这还是非常酷的。


如果确实希望程序使用模块内__all__列表之外的程序单元,有两种解决方法:

  • 第一种是使用“import 模块名”来导入模块。在通过这种方式导入模块之后,总可以通过模块名前缀(如果为模块指定了别名,则使用模块的别名作为前缀)来调用模块内的成员。
  • 第二种是使用"from 模块名 import 程序单元”来导入指定程序单元。在这种方式下,即使想导入的程序单元没有位于all列表中,也依然可以导入。

使用包

对于一个需要实际应用的模块而言,往往会具有很多程序单元,包括变量、函数和类等,如果将整个模块的所有内容都定义在同一个Python源文件中,这个文件将会变得非常庞大,显然并不利于模块化开发。

什么是包

为了更好地管理多个模块源文件,python提供了包的概念。那么什么是包呢?

  • 从物理上看,包就是一个文件夹,在该文件夹下包含了一个__init__.py文件,该文件夹可用于包含多个模块源文件
  • 从逻辑上看,包的本质依然是模块

包的作用是包含多个模块,但包的本质依然是模块,包可用于包含包。

定义包

定义包很简单,主要有两步:

  1. 创建一个文件夹,该文件夹的名字就是该包的包名
  2. 在该文件夹内添加一个 init.py文件即可

下面定义一个非常简单的包。先创建一个 first_package 文件夹,在该文件夹中添加一个 init.py 文件,该文件内容如下:

'''
这是学习包的第一个示例
'''
print('this is first_package')

该文件开始部分的字符串是该包的说明文档。通过如下程序使用该包,示例:

# 导入first_package包(模块)
import first_package

print('==========')
print(first_package.__doc__)
print(type(first_package))
print(first_package)



输出结果:
this is first_package
==========

这是学习包的第一个示例

<class 'module'>
<module 'first_package' from 'C:\\Users\\zz\\.spyder-py3\\first_package\\__init__.py'>

再次强调,包的本质就是模块,因此导入包和导入模块的语法完全相同。
从上面的输出结果可以看出,在导入first_package包时,程序执行了该包所对应的文件夹下的__init__.py;从倒数第二行输出可以看到,包的本质就是模块;从最后一行输出可以看到,使用"import first_package"导入包的本质就是加载并执行该包下的__init__.py文件,然后将整个文件内容赋值给与包同名的变量,该变量的类型是module。


与模块类似的是,包被导入之后,会在包目录下生成一个__pycache__一文件夹,并在该文件夹内为包生成一个__init__.cpython-37.pyc文件。


由于导入包就相当于导入该包下的__init__.py文件,因此我们完全可以在__init__.py文件中定义变量、函数、类等程序单元,但实际上往往并不会这么做。想一想原因是什么?包的主要作用是包含多个模块,因此__init__.py文件的主要作用就是导入该包内的其他模块。下面再定义一个更加复杂的包,在该包下将会包含多个模块,并使用__init__.py文件来加载这些模块。


新建一个 fk_package 包,包含三个模块文件:

  • arithmetic_chart.py
def print_multiple_chart(n):
    '打印乘法口角表的函数'
    for i in range(n):
        for j in range(i + 1):
            print('%d * %d = %2d' % ((j + 1) , (i + 1) , (j + 1)* (i + 1)), end='  ')
        print('')

  • billing.py
class Item:
    '定义代表商品的Item类'
    def __init__(self, price):
        self.price = price
    def __repr__(self):
        return 'Item[price=%g]' % self.price
  • print_shape.py
def print_blank_triangle(n):
    '使用星号打印一个空心的三角形'
    if n <= 0:
        raise ValueError('n必须大于0')
    for i in range(n):
        print(' ' * (n - i - 1), end='')
        print('*', end='')
        if i != n - 1:
            print(' ' * (2 * i - 1), end='')
        else:
            print('*' * (2 * i - 1), end='')
        if i != 0: 
            print('*')
        else:
            print('')

init.py 文件暂时为空,不用编写任何内容。
这意味着:fk_package 包(也是模块)总共包含这三个模块。在这种情况下,这三个模块就相当于fk_package 包的成员。

导入包内成员

# 导入fk_package包,实际上就是导入包下__init__.py文件
import fk_package
# 导入fk_package包下的print_shape模块,
# 实际上就是导入fk_package目录下的print_shape.py
import fk_package.print_shape
# 实际上就是导入fk_package包(模块)导入print_shape模块
from fk_package import billing
# 导入fk_package包下的arithmetic_chart模块,
# 实际上就是导入fk_package目录下的arithmetic_chart.py
import fk_package.arithmetic_chart

fk_package.print_shape.print_blank_triangle(5)
im = billing.Item(4.5)
print(im)
fk_package.arithmetic_chart.print_multiple_chart(5)


输出结果:
    *
   * *
  *   *
 *     *
*********
Item[price=4.5]
1 * 1 =  1  
1 * 2 =  2  2 * 2 =  4  
1 * 3 =  3  2 * 3 =  6  3 * 3 =  9  
1 * 4 =  4  2 * 4 =  8  3 * 4 = 12  4 * 4 = 16  
1 * 5 =  5  2 * 5 = 10  3 * 5 = 15  4 * 5 = 20  5 * 5 = 25  


# 从当前包导入print_shape模块
from . import print_shape
# 从.print_shape导入所有程序单元到fk_package中
from .print_shape import *
# 从当前包导入billing模块
from . import billing
# 从.billing导入所有程序单元到fk_package中
from .billing import *
# 从当前包导入arithmetic_chart模块
from . import arithmetic_chart
# 从.arithmetic_chart导入所有程序单元到fk_package中
from .arithmetic_chart import *
# 导入fk_package包,实际上就是导入包下__init__.py文件
import fk_package

# 直接使用fk_package前缀即可调用它所包含的模块内的程序单元。
fk_package.print_blank_triangle(5)
im = fk_package.Item(4.5)
print(im)
fk_package.print_multiple_chart(5)

输出结果:

    *
   * *
  *   *
 *     *
*********
Item[price=4.5]
1 * 1 =  1  
1 * 2 =  2  2 * 2 =  4  
1 * 3 =  3  2 * 3 =  6  3 * 3 =  9  
1 * 4 =  4  2 * 4 =  8  3 * 4 = 12  4 * 4 = 16  
1 * 5 =  5  2 * 5 = 10  3 * 5 = 15  4 * 5 = 20  5 * 5 = 25  

上面粗体字代码是导入fk_package包,导入该包的本质就是导入该包下的__init__.py文件。而__init__.py文件又执行了导入,它们会把三个模块内的程序单元导入fk_package包中,因此程序的下面代码可使用fk_package.前缀来访问三个模块内的程序单元。

查看模块内容

在导入模块之后,开发者往往需要了解模块包含哪些功能,比如包含哪些变量、哪些函数、哪些类等,还希望能查看模块中各成员的帮助信息,掌握这些信息才能正常地使用该模块。

模块包含什么

为了查看模块包含什么,可以通过如下两种方式:

  • 使用dir()函数 (返回模块或类所包含的全部程序单元,包括变量、函数、类和方法等)
  • 使用模块本身提供的__all__变量
import string

dir(string)
Out[24]: 
['Formatter',
 'Template',
 '_ChainMap',
 '_TemplateMetaclass',
 '__all__',
 '__builtins__',
 '__cached__',
 '__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 '_re',
 '_string',
 'ascii_letters',
 'ascii_lowercase',
 'ascii_uppercase',
 'capwords',
 'digits',
 'hexdigits',
 'octdigits',
 'printable',
 'punctuation',
 'whitespace']

很明显,该模块内有大量以下划线开头的程序单元,其实这些程序单元并不希望被其他程序使用,因此列出这些程序单元意义不大,可以使用列表推导式过滤掉,示例:

[e for e in dir(string) if not e.startswith('_')]
Out[25]: 
['Formatter',
 'Template',
 'ascii_letters',
 'ascii_lowercase',
 'ascii_uppercase',
 'capwords',
 'digits',
 'hexdigits',
 'octdigits',
 'printable',
 'punctuation',
 'whitespace']

也可通过该模块的__all__变量来查看模块内的程序单元(有些模块不提供__all__变量,只能使用上面列表推导式来查看),如下

tring.__all__
Out[26]: 
['ascii_letters',
 'ascii_lowercase',
 'ascii_uppercase',
 'capwords',
 'digits',
 'hexdigits',
 'octdigits',
 'printable',
 'punctuation',
 'whitespace',
 'Formatter',
 'Template']

使用__doc__属性查看文档

使用help()函数之所以能查看到程序单元的帮助信息,其实完全是因为该程序单元本身有文档信息,也就是有__doc__属性。换句话说,使用help()函数查看的其实就是程序单元的__doc__属性值。
提示:Python库的参考文档:https://docs.python.org/3/library/index.html

使用__file__属性查看模块的源文件路径

通过模块的__file__属性即可查看到指定模块的源文件路径。开发者完全可以根据路径打开查看该模块的全部源代码。
需要说明的是,并不是所有模块都是使用Python语言编写的,有些与底层交互的模块可能是用C语言编写的,而且是C程序编译之后的效果,因此这种模块可能没有__file__属性。


原文来源于我的语雀,我的微信公众号:细细研磨

原文地址:https://www.cnblogs.com/onelikeone/p/15162999.html