Python基础 --【模块】

236 阅读9分钟

1、模块的介绍

  • 在python中以扩展名py为结尾的文件就是一个模块

  • 模块名同样也是一个标识符,需要符合标识符的命名规则

  • 在模块中定义的全局变量、函数、类都是提供给外界直接使用的工具

  • 模块就好比工具包,要想使用这个工具包中工具,就需要先导入这个模块

2、模块的导入方式

导入模块是指:
◆ 在一个.py文件中,使用另外一个.py文件时,需要将这个文件导入
◆ 在一个模块中,使用另外一个模块时,需要将这个模块导入

① import 模块名

  • 在使用import 模块名导入模块时,会将整个文件导入成一个模块对象
  • 在使用模块中的成员(全局变量、函数、类)时,需要使用模块名.成员名

语法格式

在导入模块时,每个导入的模块应该独占一行(推荐使用)

import 模块名1
import 模块名2

以下这种(不推荐使用)

import 模块名1,模块名2

示例1

第一步:新建一个自定义模块(user_defined.py)

# 可以定义全局变量 
a = 1 

# 可以定义函数 
def func(): 
    print("hello python!") 

# 可以定义类 
class show(object): 
    def func(self): 
        print("hello world") 

print(a) 
func() 
b = show() 
b.func()

第二步:新建一个测试模块(test.py)用来使用自定义模块

# 先导入user_defined模块,不写其他代码,先运行测试结果
import user_defined 

######结果###### 
1 
hello python! 
hello world

通过结果说明:模块是一个对象,在导入模块时,创建了该模块的对象,也就会去执行该模块中的所有文件。

示例2

第一步:新建一个自定义模块(user_defined.py)

# 定义全局变量 
a = 1 

# 定义函数 
def func(): 
    print("hello python!") 

# 定义类 
class show(object): 
    def func(self): 
        print("hello world")

第二步:新建一个测试模块(test.py)用来使用自定义模块

import user_defined 

# 使用模块名.变量调用user_defined模块中的变量 
print(user_defined.a) 

# 使用模块名.函数调用user_defined模块中的函数 
user_defined.func() 

# 使用模块名.类名()来实例化user_defined模块中的类 
b = user_defined.show() 
b.func() 

######结果###### 
1 
hello python! 
hello world

通过结果说明:import-模块名的方式要想使用模块中的成员,通过模块名.成员调用。

② import别名形式

问: 为什么要用别名形式???
答: 别名就是为复杂的模块名起一个代号,可以通过这个代号来调用模块名中的相应的成员。比如有个模块名:abcddfgsdflsdfsdfasdf,调用模块中成员非常麻烦,这时候就可以用as取一个别名来调用成员。

示例

第一步:新建一个自定义模块(user_defined.py)

# 定义全局变量 
a = 1 

# 定义函数 
def func(): 
    print("hello python!") 
    
# 定义类 
class show(object): 
    def func(self): 
        print("hello world")

第二步:新建一个测试模块(test.py)用来使用自定义模块

导入user_defined模块并起一个别名为b 
import user_defined as b 

# 使用别名.变量调用user_defined模块中的变量 
print(b.a) 

# 使用别名.函数调用user_defined模块中的函数 
b.func() 

# 使用别名.类名()来实例化user_defined模块中的类 
c = b.show()  
# 如果类只调用一次方法可以使用匿名函数:b.show().func(),不用变量接收。
# 如果写两次内存地址不一样 

c.func()

③ from 模块名 import 成员名

问: 已经有了import导入模块,为什么还需要from 模块名 import 成员名 这个导入方式
答: import 代表导入某个或多个模块中的所有功能,但是有些情况下,我们只希望使用这个模块下的某些方法。而不需要全部导入,这个时候就建议采用from 模块名 import 成员

◆ from-import方式导入的是指定模块中的指定成员
◆ 当使用from-import方式导入时,不需要再使用 模块名.成员 调用成员。可以在当前文件中直接使用成员名,相当于将导入的模块复制到本地一份。

示例

第一步:新建一个自定义模块(user_defined.py)

# 定义全局变量 
a = 1 

# 定义函数 
def func(): 
    print("hello python!") 
    
# 定义类 
class show(object): 
    def func(self): 
        print("hello world")

第二步:新建一个测试模块(test.py)使用from-import方式调用成员

# 使用from-import方式导入模块中的a方法 
from user_defined import a 

# 直接打印变量a,不需要再用 模块名.成员 的方式调用成员
print(a) 

######结果###### 
1

这个时候调用 fun() 函数

# 使用from-import方式导入模块中的a变量 
from user_defined import a 

# 直接打印变量a,不需要再用 模块名.成员 的方式调用成员 
print(a) 

# 调用func函数 
func() 

######结果###### 
1 
报错

为什么报错呢? 没有导入模块中 func函数 成员

# 使用from-import方式导入模块中的a变量和func函数 
from user_defined import a 
from user_defined import func 

# 直接打印变量a,不需要再用 模块名.成员 的方式调用成员 
print(a)

func() 

######结果###### 
1 
hello python!

④ from-import 别名形式

语法格式:

from 模块名 import 成员名 as 别名 
from 模块名 import 成员名 as 别名, 成员名 as 别名……

示例:

第一步:新建一个自定义模块(user_defined.py)

# 定义函数 
def func(): 
    print("hello python!")

第二步:新建一个测试模块(test.py)

# 使用from-import方式导入模块中func函数并取别名f 
from user_defined import func as f 

# 调用函数 
f()

######结果###### 
hello python!

⑤ from 模块名 import*

◆ 使用import时,可以将整个模块中的成员都导入进来
◆ 如果使用from-import时,可以使用哪个成员导入哪个成员,这样更加节省资源。
◆ 如果想使用from - import方式导入所有成员,可以使用from 模块名 import ∗
◆ 如果使用通配符*的方式导入所有成员,那么就不能使用 as 为成员取别名

示例:

第一步:新建一个自定义模块(user_defined.py)

# 定义全局变量 
a = 1 

# 定义函数 
def func(): 
    print("hello python!") 
    
# 定义类 
class show(object): 
    def func(self): 
        print("Hi world")

第二步:新建一个测试模块(test.py)使用from-import *方式调用成员

# 使用from-import *方式导入模块所有成员 
from user_defined import * 

# 调用成员 
print(a) 
func() 
show().func() 

######结果###### 
1 
hello python! 
Hi python!

3、两种导入方式区别

1.import方式,是拿到了模块对象的引用地址,通过这个引用地址来使用模块中的成员;
2.from-import方式,相当于将被导入模块中的成员,复制一份到本地模块中,所有可以直接使用成员来访问被导入的成员;
3.对于impot方式来说没有任何限制;
4.对于from-import方式来说,有些成员是不能被导入的(有权限限制)

示例: 验证3和4

第一步:新建一个自定义模块(user_defined.py)

# 全局变量:模块间的公有变量
a = 1 

# _私有变量:文件内私有变量
_b = 2

# __私有变量:一般出现在类中
__c = 3

第二步:新建一个测试模块(test.py)

# 使用import方式导入模块
import user_defined 

# 调用成员 
print(user_defined.a) 
print(user_defined._b)
print(user_defined.__c)

######结果###### 
1 
2
3
# 使用from-import *方式导入模块所有成员 
from user_defined import * 

# 调用成员 
print(a) 
print(_b)
print(__c)

######结果###### 
1 
报错
报错

通过结果说明:在使用from-import方式导入模块时,不会将私有属性导入。 但是可以通过__all__这个魔法属性,可以改变from-import的导入规则(一般不会在这里去使用__all__属性)

示例:

第一步:新建一个自定义模块(user_defined.py)

# 全局变量:模块间的公有变量
a = 1 

# _私有变量:文件内私有变量
_b = 2

# __私有变量:一般出现在类中
__c = 3

# 使用__all__方法改变from-import方式的导入规则
__all__ = ["_b","__c"]

第二步:新建一个测试模块(test.py)

# 使用from-import *方式导入模块所有成员 
from user_defined import * 

# 调用成员 
print(a) 
print(_b)
print(__c)

######结果###### 
报错
2
3

4、from import方式的命名冲突

当我们编写多个模块时,可能在导入到其他页面时,会产生一个问题:全局变量、函数、类出出现重名情况,我们把这个情况就称之为“命名冲突”。

示例

第一步:新建两个模块

module1.py

def func():
    print("module1中的方法")

module2.py

def func():
    print("module2中的方法")

第二步:新建一个测试模块(test.py)导入module1和module2模块

from module1 import func
from module2 import func

# 导入func方法
func()

######结果######
module2中的方法

通过结果说明:导入的module1和module2里面都封装了一个func()方法,其中在导入后,module2中的func()就会覆盖module1中的func()。命名冲突是后面的会覆盖前面的。

解决方法:

  • 使用import方式导入
  • 修改成员名
  • 给重名的方法用as重命名

5、模块导入顺序

查找顺序

1.当前程序所在目录
2.在当前程序所在工程的根目录
3.PYTHONPATH
4.系统目录
5.site_packages 第三方模块的安装目录

6、设置程序入口

当使用__name__属性在获取当前模块名时,会有两种效果

  • 如果当前模块文件是主动执行时,__name__ 得到的结果是字符串 __main__ 表示这是程序的入口;
  • 如果当前模块文件是被动执行时(被别人导入时),__name__ 得到的结果就是当前模块文件的文件名。

示例:

第一步:新建一个自定义模块(user_defined.py)并运行结果

print("name:",__name__)

######结果######
name: __main__

通过结果说明:直接运行python程序时,__name__的值为__main__

第二步:新建一个测试模块(test.py)导入模块并运行结果

import user_defined

######结果######
name: user_defined

通过结果说明:其他程序导入.py文件运行时,__name的值为文件名,即模块名。

作用: 依据该特性,最直接的作用就是,区分py文件直接被执行,还是被引入其他程序中。

应用
项目需求生成求和的模块,程序编写过程,通常会在程序中写上一些测试脚本,来验证程序是否正确。

第一步:新建一个自定义模块(user_defined.py)并运行测试结果

# 定义一个求和函数
def sums(a, b):
    result = a + b
    return result

# 以下针对模块的测试信息
c = sums(3, 4)
print(c)

######结果######
7

产生问题 那么这样就产生了一个问题,其他人在调用这个模块的时候,测试内容也会打印出来。当然可以在提交代码前,删除这些用于测试的代码。不过通常提交以后,可能会因为一些BUG,或者需求本身进行了调整,代码需要重新修改,那么测试代码也可能被再次添加。如此反复自然就徒增一些代码量。

解决方案 只要在测试代码前面加上:if __name__ == '__main__':那么,编写调试过程直接运行该模块时__name__ 的值为__main__ ",即测试内容被执行。而在导入该模块,__name__ 的值为py文件名,测试内容则不会被执行。

# 定义一个求和函数
def sums(a, b):
    result = a + b
    return result

# 程序被导入,以下代码不会被执行
if __name__ == '__main__':
    c = sums(3, 4)
    print(c)