购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

5.2 模块

模块是Python中重要的概念,Python的程序是由一个个模块组成的。前面已经接触到了模块,一个Python文件就是一个模块。下面将介绍模块的概念和特性。

5.2.1 模块的创建

模块把一组相关的函数或代码组织到一个文件中。一个文件即是一个模块。模块由代码、函数或类组成。创建一个名为myModule.py的文件,即定义了一个名为myModule的模块。在myModule模块中定义一个函数func()和一个类MyClass。MyClass类中定义一个方法myFunc()。


01     # 自定义模块
02     def func():                                             # 定义func函数
03         print ("MyModule.func()")
04
05     class MyClass:                                        # 定义MyClass类
06         def myFunc(self):                                   # 定义myFunc方法
07             print ("MyModule.MyClass.myFunc()")          # 调用myFunc()方法

然后在myModule.py所在的目录下创建一个call_myModule.py的文件。在该文件中调用myModule模块的函数和类。


01     #调用自定义模块的类和函数
02     import myModule      # 导入moudle
03
04     myModule.func()
05     myClass = myModule.MyClass()
06     myClass.myFunc()

【代码说明】

·第2行代码导入模块myModule。

·第4行调用模块的函数。调用时需要加前缀myModule,否则Python不知道func()所在的命名空间。输出结果:


myModule.func()

·第5行代码创建类MyClass的实例myClass。这里也需要使用前缀myModule调用类。

·第6行调用类的方法myFunc()。输出结果:


myModule.MyClass.myFunc()

注意 myModule.py和call_myModule.py必须放在同一个目录下,或放在sys.path所列出的目录下;否则,Python解释器找不到自定义的模块。

当Python导入一个模块时,Python首先查找当前路径,然后查找lib目录、site-packages目录(Python\Lib\site-packages)和环境变量PYTHONPATH设置的目录。如果导入的模块没有找到,在以上路径搜索一下是否含有这个模块。可以通过sys.path语句搜索模块的查找路径。

5.2.2 模块的导入

在使用一个模块的函数或类之前,首先要导入该模块。前面已经多次使用模块的导入,模块的导入使用import语句。模块导入语句的格式如下所示。


import module_name

这条语句可以直接导入一个模块。调用模块的函数或类时,需要以模块名作为前缀,其格式如下所示。


module_name.func()

如果不想在程序中使用前缀符,可以使用from…import…语句导入。from…import…语句的格式如下所示。


from module_name import function_name

2.2.3小节比较了import语句和from…import…语句的不同。导入模块下所有的类和函数,可以使用如下格式的import语句。


from module_name import *

此外,同一个模块文件支持多条import语句。例如,定义一个名为myModule的模块。该模块定义一个全局变量count和一个函数func()。每次调用函数func(),使变量count的值加1。


01     count = 1                    # 定义全局变量count并赋值
02
03     def func():                    # 定义func函数
04         global count
05         count = count + 1
06         return count

多次导入myModule模块,查看变量count的结果。


01     import myModule
02     print("count =", myModule.func())
03     myModule.count = 10
04     print ("count =", myModule.count)
05
06     import myModule
07     print ("count =", myModule.func())

【代码说明】

·第1行代码导入模块myModule。

·第2行代码调用模块中的函数func()。此时变量count的值等于2。输出结果:count=2。

·第3行代码给模块myModule中的变量count赋值,此时变量count的值等于10。

·第4行代码获取变量count的值。输出结果:count=10。

·第6行代码再次导入模块myModule,变量count的初始值为10。

·第7行代码调用func(),变量count的值加1。输出结果:count=11。

Python中的import语句比Java的import语句更灵活。Python的import语句可以置于程序中任意的位置,甚至可以放在条件语句中。在上面的代码段后添加如下语句:


01     # import置于条件语句中
02     if myModule.count > 1:
03         myModule.count = 1
04     else:
05         import myModule
06     print ("count =", myModule.count)

【代码说明】

·第2行代码判断myModule.count的值是否大于1。

·第3行代码,如果count的值大于1,则把变量count的值置为1。由于前面代码段中变量count的值为11,所以变量count的值被赋值为1。

·第5行代码,如果count的值小于等于1,则导入import语句。

·第6行代码输出变量count的值。输出结果:count=1

5.2.3 模块的属性

模块有一些内置属性,用于完成特定的任务,如__name__、__doc__。每个模块都有一个名称,例如,__name__用于判断当前模块是否是程序的入口,如果当前程序正在被使用,__name__的值为“__main__”。通常给每个模块都添加一个条件语句,用于单独测试该模块的功能。例如,创建一个模块myModule。


01     if __name__ == '__main__':
02         print ('myModule作为主程序运行')
03     else:
04         print ('myModule被另一个模块调用')

【代码说明】 第1行代码判断本模块是否作为主程序运行。单独运行模块myModule,输出结果如下所示。


myModule作为主程序运行

创建另一个模块call_myModule。这个模块很简单,只要导入模块myModule即可。


01     import myModule
02     print (__doc__)

【代码说明】 运行模块call_myModule,输出结果:


myModule被另一个模块调用

第2行代码调用了模块另一个属性__doc__。由于该模块没有定义文档字符串,所以输出结果为None。输出结果:None

5.2.4 模块的内置函数

Python提供了一个内联模块buildins。内联模块定义了一些开发中经常使用的函数,通过dir(buildins)可以查看内联模块中所有的内置函数,利用这些函数可以实现数据类型的转换、数据的计算、序列的处理等功能。下面将介绍内联模块中常用的函数。

1.apply()

Python3中移除了apply函数,所以不再可用了。调用可变参数列表的函数的功能只能使用在列表前添加*来实现。

2.filter()

filter()可以对某个序列做过滤处理,判断自定义函数的参数返回的结果是否为真来过滤,并一次性返回处理结果。filter()的声明如下所示。


class filter(object)
     filter(function or None, iterable) --> filter object

下面这段代码演示了filter()过滤序列的功能。从给定的列表中过滤出大于0的数字。


01     def func(x):                                                # 定义func函数
02         if x > 0:                                              # if判断
03             return x                                           # 返回x的值
04
05     print (filter(func, range(-9, 10)))                # 调用filter函数,返回的是filter对象
06   print(list(filter(func, range(-9, 10)))            # 将filter对象转换为列表

【代码说明】 第5行代码,使用range()生成待处理的列表,然后把该列表的值依次传入func()。func返回结果给filter(),最后将结果yield成一个iterable对象返回,可以进行遍历。输出结果如下。


<filter object at 0x0000019C68C88948>

直接打印出的是filter对象,无法看出其内容。第6行将其转换为列表。输出结果如下。


[1, 2, 3, 4, 5, 6, 7, 8, 9]

注意 filter()中的过滤函数func()的参数不能为空。否则,没有可以存储sequence元素的变量,func()也不能处理过滤。

3.reduce()

对序列中元素的连续操作可以通过循环来处理。例如,对某个序列中的元素累加操作。Python提供的reduce()也可以实现连续处理的功能。在Python2中reduce()存在于全局空间中,可以直接调用。而在Python3中将其移到了functools模块中,所以使用之前需要先引入。reduce()的声明如下所示。


reduce(func, sequence[, initial]) -> value

【代码说明】

·参数func是自定义的函数,在函数func()中实现对参数sequence的连续操作。

·参数sequence待处理的序列。

·参数initial可以省略,如果initial不为空,则initial的值将首先传入func()进行计算。如果sequence为空,则对initial的值进行处理。

·reduce()的返回值是func()计算后的结果。

下面这段代码实现了对一个列表的数字进行累加的操作。


01     def sum(x, y):                                             # 定义sum函数
02         return x + y                                      # 返回x + y的值
03     from functools import reduce                          # 引入reduce
04     print (reduce(sum, range(0, 10)))
05     print (reduce(sum, range(0, 10), 10))
06     print (reduce(sum, range(0, 0), 10))

【代码说明】

·第1行代码,定义了一个sum()函数,该函数提供两个参数,执行累加操作。

·第4行代码,对0+1+2+3+4+5+6+7+8+9执行累加计算。输出结果为45。

·第5行代码,对10+0+1+2+3+4+5+6+7+8+9执行累加计算。输出结果为55。

·第6行代码,由于range(0,0)返回空列表,所以返回结果就是10。输出结果为10。

reduce()还可以对数字进行乘法、阶乘等复杂的累计计算。

注意 如果用reduce()进行累计计算,必须在sum中定义两个参数,分别对应加法运算符两侧的操作数。

4.map()

第4章使用了map()对tuple元组进行“解包”操作,调用时设置map()的第一个参数为None。map()的功能非常强大,可以对多个序列的每个元素都执行相同的操作,并返回一个map对象。map()的声明如下所示。


class map(object)
   map(func, *iterables) --> map object

【代码说明】

·参数func是自定义的函数,实现对序列每个元素的操作。

·参数iterables是待处理的序列,参数iterables的个数可以是多个。

·map()的返回值是对序列元素处理后的列表。

下面这段代码实现了列表中数字的幂运算。


01     def power(x): return x ** x                                         # 定义power函数
02     print (map(power, range(1, 5)))                                       # 打印map对象
03     print(list(map(power,range(1,5))))                                   # 转换为列表输出
04     def power2(x, y): return x ** y
05     print (map(power2, range(1, 5), range(5, 1, -1)))                   # 打印map对象
06     print(list(map(power2, range(1, 5), range(5, 1, -1))))             # 转换为列表输出

【代码说明】

·第1行代码定义了一个power()函数,实现了数字的幂运算。

·第2行代码把数字1、2、3、4依次传入函数power中,将计算结果yield成一个iterable对象,输出结果:


<map object at 0x0000020A24765148>

·第3行代码将map对象转换为列表然后打印出来,输出结果:


[1, 4, 27, 256]

·第4行代码,定义了一个power2()函数,计算x的y次幂。

·第5行代码,提供了两个列表参数。依次计算1^5、2^4、3^3、4^2,计算后的结果同样yield成一个iterable对象。输出结果:


<map object at 0x0000020A24765B48>

·第6行代码将map对象转换成为列表输出。输出结果:


[1, 16, 27, 16]

注意 如果map()中提供多个序列,则每个序列中的元素一一对应进行计算。如果每个序列的长度不相同,则短的序列后补充None,再进行计算。

常用内置函数一览表如表5-1所示。

表5-1 内置模块的函数

5.2.5 自定义包

包就是一个至少包含__init__.py文件的文件夹。Python包和Java包的作用是相同的,都是为了实现程序的重用,把实现一个常用功能的代码组合到一个包中,调用包提供的服务从而实现重用。例如,定义一个包parent。在parent包中创建两个子包pack和pack2。pack包中定义一个模块myModule,pack2包中定义一个模块myModule2。最后在包parent中定义一个模块main,调用子包pack和pack2,如图5-2所示。

图5-2 包与模块的树形关系图

【例5-1】通过代码完成自定义包。包pack的__init__.py程序如下所示。

【例5-1.py】


01     if __name__ == '__main__':                    # 判断本模块是否作为主程序运行
02         print ('作为主程序运行')
03     else:
04         print ('pack初始化')

这段代码初始化pack包,这里直接输出一段字符串。当pack包被其他模块调用时,将输出“pack初始化”。包pack的myModule模块如下所示。


01     def func():                                   # 定义func函数
02         print ("pack.myModule.func()")
03
04     if __name__ == '__main__':                    # 判断本模块是否作为主程序运行
05         print ('myModule作为主程序运行')
06     else:
07         print ('myModule被另一个模块调用')

当pack2包被其他模块调用时,将首先执行__init__.py文件。pack2包的__init__.py程序如下。


01     if __name__ == '__main__':
02         print ('作为主程序运行')
03     else:
04         print ('pack2初始化')

包pack2的myModule2模块如下。


01     def func2():                                   # 定义func2函数
02         print ("pack2.myModule2.func()")
03
04     if __name__ == '__main__':                    # 判断本模块是否作为主程序运行
05         print ('myModule2作为主程序运行')
06     else:
07         print ('myModule2被另一个模块调用')

下面的main模块调用了pack、pack2包中的函数。


01     from pack import myModule
02     from pack2 import myModule2
03
04     myModule.func()
05     myModule2.func2()

【代码说明】

·第1行代码从pack包中导入myModule模块,myModule模块被main模块调用,因此输出字符串“myModule被另一个模块调用”。输出结果如下。


pack初始化
myModule被另一个模块调用

·第2行代码从pack2包中导入myModule2模块。输出结果如下。


pack2初始化
myModule2被另一个模块调用

·第4行代码调用myModule模块的函数func()。输出结果如下。


pack.myModule.func()

·第5行代码调用myModule2模块的函数func2()。输出结果如下。


pack2.myModule2.func()

__init__.py也可以用于提供当前包的模块列表。例如,在pack包的__init__.py文件前面添加一行代码。


__all__ = ["myModule"]

__all__用于记录当前pack包所包含的模块。其中方括号中的内容是模块名的列表,如果模块数量超过2两个,使用逗号分开。同理,在pack2包也添加一行类似的代码。


__all__ = ["myModule2"]

这样就可以在main模块中一次导入pack、pack2包中所有的模块。修改后的main模块如下。


01     from pack import *
02     from pack2 import *
03
04     myModule.func()
05     myModule2.func2()

【代码说明】

·第1行代码,首先执行pack包的__init__.py文件,然后在__all__属性中查找pack包含有的模块。如果pack包的__init__.py文件不使用__all__属性记录模块名,main模块调用时将不能识别myModule模块。Python将提示如下错误。


NameError: name 'myModule' is not defined

·第2行代码与第1行代码的作用相同。 BHVWv5i91xqMzExJWJ6iswsNwjFFmnPvBjxMS2Zqyvqnz53bDY8/2XYI/EcGvHBY

点击中间区域
呼出菜单
上一章
目录
下一章
×