Python3快速入门—4.包和模块

4.包和模块

4.1包和模块的含义

在Python中,项目的组织结构从高到低依次是:包->模块->类->函数/变量。类和函数在后面的章节中讲解,本章主要讲包和模块。

Python包:Python项目下,包含__init__.py文件的文件夹,简称”Package”。

模块:Python项目下,包含Python代码的.py文件,简称”Module”。

Python包可以理解为文件夹,但Python包和文件夹之间还是有差别的。当一个文件夹包含了__init__.py文件,此时这个文件夹可以称为Python包。__init__.py的作用之一就是为了区分Python包和文件夹,即使__init__.py中什么也不写。

模块可以理解为后缀名是py的文件。

|--Python_Demo

|--pack1

p1_mod1.py

|--pack2

p2_mod1.py

mod1.py

main.py

pack1和pack2并不是Python包,因为内部没有包含__init__.py文件。

|--Python_Demo

|--pack1

p1_mod1.py

__init__.py

|--pack2

p2_mod1.py

__init__.py

mod1.py

main.py

pack1和pack2是Python包,因为其内部包含__init__.py文件;目录中以py为后缀名的都是模块。

4.2模块的导入

4.2.1 import语句

使用import语句来导入模块,使用运算符(.)来访问模块中的函数、变量等。

目录结构:

|--Python_Demo

|--pack1

p1_mod1.py

__init__.py

|--pack2

p2_mod1.py

__init__.py

mod1.py

main.py

# this is main.py

import mod1

 

print('main.py')

print('a = %d'%mod1.a,'b = %d'%mod1.b,'c = %d'%mod1.c)

# this is mod1.py

print('mod1.py')

a = 1

b = 2

c = 3

执行main.py的运行结果:

mod1.py

main.py

a = 1 b = 2 c = 3

模块的导入可以理解为py文件的拼接,在main.py文件中导入了mod1.py模块,相当于main.py文件上拼接了mod1.py。当开始执行时,会先执行mod1.py,再去执行main.py。

当模块导入后,可以使用运算符(.)来访问模块中的函数、变量。上述代码中,在main.py访问mod1.py中的a/b/c,需要加上模块名。

# this is main.py

import pack1.p1_mod1

 

print('main.py')

print('a = %d'%pack1.p1_mod1.a,'b = %d'%pack1.p1_mod1.b,'c = %d'%pack1.p1_mod1.c)

# this is p1_mod1.py

print('p1_mod1.py')

a = 1

b = 2

c = 3

执行main.py的运行结果:

p1_mod1.py

main.py

a = 1 b = 2 c = 3

当导入包(Package)内部的模块,import时需要加上package.module(模块的绝对路径);使用模块函数、变量时也需要加上package.module。

那么执行文件、模块、包和目录之间到底有什么关系呢?

目录结构:

|--Python_Demo

|--pack1

p1_mod1.py

__init__.py

|--pack2

p2_mod1.py

__init__.py

mod1.py

main.py

test.py

在上述目录中,main.py会被执行。其中,main.py被称为“入口文件”或“主模块”,main.py所在的目录称为“顶层目录”。

Python_Demo、test.py的目录等级相同;pack1、pack2、mod1.py、main.py的目录等级相同;p1_mod1.py、__init__.py的目录等级相同;p2_mod1.py、__init__.py的目录等级相同。

当以main.py为入口文件时,其上级目录中的模块无法被识别和导入,如test.py;其同级或下级目录中的模块可以被任意导入,即使下级目录的模块也可以导入同级目录的模块,举例:main.py->p1_mod1.py->p2_mod1.py->mod1.py。

# this is main.py

import pack1.p1_mod1

 

print('main.py')

print('p1m1 = %d'%pack1.p1_mod1.p1m1)

# this is pack1->p1_mod1.py

import pack2.p2_mod1

 

print('pack1->p1_mod1.py')

print('p2m1 = %d'%pack2.p2_mod1.p2m1)

p1m1 = 11

# this is pack2->p2_mod1.py

import mod1

 

print('pack2->p2_mod1.py')

print('m1 = %d'%mod1.m1)

p2m1 = 21

# this is mod1.py

print('mod1.py')

m1 = 1

main.py的执行结果:

mod1.py

pack2->p2_mod1.py

m1 = 1

pack1->p1_mod1.py

p2m1 = 21

main.py

p1m1 = 11

4.2.2 import...as...语句

当导入模块后,调用模块内的函数、变量都需要加package.module(模块的绝对路径)。若package.module名称过长,导致每次调用都很不方便,因此可以使用import...as...语句。

目录结构:

|--Python_Demo

|--pack1

p1_mod1.py

__init__.py

|--pack2

p2_mod1.py

__init__.py

mod1.py

main.py

# this is main.py

import pack1.p1_mod1 as pm

 

print('main.py')

print('a = %d'%pm.a,'b = %d'%pm.b,'c = %d'%pm.c)

# this is p1_mod1.py

print('p1_mod1.py')

a = 1

b = 2

c = 3

执行main.py的运行结果:

p1_mod1.py

main.py

a = 1 b = 2 c = 3

4.2.3 from...import...语句

当我们不想把整个模块都导入时,可以使用from...import...选择性导入变量、函数。

目录结构:

|--Python_Demo

|--pack1

p1_mod1.py

__init__.py

|--pack2

p2_mod1.py

__init__.py

mod1.py

main.py

# this is main.py

from pack1.p1_mod1 import a,b,c

 

print('main.py')

print('a = %d'%a,'b = %d'%b,'c = %d'%c)

# this is p1_mod1.py

print('p1_mod1.py')

a = 1

b = 2

c = 3

执行main.py的运行结果:

p1_mod1.py

main.py

a = 1 b = 2 c = 3

使用from...import...导入模块函数、变量,其使用不需要再加package.module(模块的绝对路径),可以直接使用。优点:使用函数、变量比较方便。

若函数、变量前没有package.module,若导入模块和入口文件发生名称冲突该怎么办?

目录结构:

|--Python_Demo

|--pack1

p1_mod1.py

__init__.py

|--pack2

p2_mod1.py

__init__.py

mod1.py

main.py

# this is main.py

from pack1.p1_mod1 import a,b,c

 

print('main.py')

print('a = %d'%a,'b = %d'%b,'c = %d'%c)

 

a = 4

b = 5

c = 6

print('a = %d'%a,'b = %d'%b,'c = %d'%c)

# this is p1_mod1.py

print('p1_mod1.py')

a = 1

b = 2

c = 3

执行main.py的运行结果:

p1_mod1.py

main.py

a = 1 b = 2 c = 3

a = 4 b = 5 c = 6

名称冲突:main.py中的变量a/b/c对pack1.p1_mod1的变量a/b/c重新赋值,即覆盖。因为pack1.p1_mod1先执行,main.py后执行。

4.2.4 from...import *语句

使用from...import *和import ...的作用是相同的,一个是从变量、函数层数全部导入,一个是导入整个模块。

但from...import *可以和__all__一起使用。在__all__中可以指定哪些变量、函数可以被from...import *导出。

目录结构:

|--Python_Demo

|--pack1

p1_mod1.py

__init__.py

|--pack2

p2_mod1.py

__init__.py

mod1.py

main.py

# this is main.py

from pack1.p1_mod1 import *

 

print('main.py')

print('a = %d'%a,'b = %d'%b)

# this is p1_mod1.py

__all__ = ['a','b']

 

print('p1_mod1.py')

a = 1

b = 2

c = 3

执行main.py的运行结果:

p1_mod1.py

main.py

a = 1 b = 2

4.3 __pycache__的隐藏和__init__.py的使用

4.3.1隐藏__pycache__

当在Python代码中导入模块时,会产生*.pyc文件。*.pyc文件的作用是提高模块的加载速度,但不会提高代码的执行速度。

为了避免__pycache__对Python项目文件的影响,可以将其隐藏。

选择“文件”->“首选项”->“设置”,输入”exclude”,在用户设置的Files:Exclude中添加模式**/__pycache__即可。

4.3.2 __init__.py的用法

当导入包内部的模块时,它会最先导入__init__.py。

目录结构:

|--Python_Demo

|--pack1

p1_mod1.py

__init__.py

|--pack2

p2_mod1.py

__init__.py

mod1.py

main.py

# this is main.py

import pack1.p1_mod1 as pm

 

print('main.py')

print('a = %d'%pm.a,'b = %d'%pm.b,'c = %d'%pm.c)

# this is __init__.py

print('__init__.py')

# this is p1_mod1.py

print('p1_mod1.py')

a = 1

b = 2

c = 3

执行main.py的运行结果:

__init__.py

p1_mod1.py

main.py

a = 1 b = 2 c = 3

可以看到在导入p1_mod1.py之前,导入了__init__.py模块。

__init__.py用法1:__all__配合from package import *使用。

|--Python_Demo

|--pack1

p1_mod1.py

__init__.py

|--pack2

p2_mod1.py

__init__.py

mod1.py

main.py

# this is main.py

from pack1 import *

 

print('main.py')

print('a = %d'%p1_mod1.a,'b = %d'%p1_mod1.b,'c = %d'%p1_mod1.c)

# this is __init__.py

print('__init__.py')

__all__ = ['p1_mod1']

# this is p1_mod1.py

print('p1_mod1.py')

a = 1

b = 2

c = 3

执行main.py的运行结果:

__init__.py

p1_mod1.py

main.py

a = 1 b = 2 c = 3

这里需要注意的是from package import *是导入包内部的全部模块,必须配合__all__使用,不然一个模块都无法导入。而from package.module import *是导入模块内的全部变量,可以使用或不使用__all__。

__init__.py用法2:使用import package来导入Python标准库。

目录结构:

|--Python_Demo

|--pack1

p1_mod1.py

__init__.py

|--pack2

p2_mod1.py

__init__.py

mod1.py

main.py

# this is main.py

import pack1

 

print('main.py')

print('math.pi = %f'%pack1.math.pi)

# this is __init__.py

import math

import sys

import os

 

print('__init__.py')

执行main.py的运行结果:

__init__.py

main.py

math.pi = 3.141593

使用import package只会导入包内部的__init__.py模块(其他模块无法导入),在__init__.py中可以设置需要导入的Python标准库。

注:当然也可以使用前面的from package import *方法,在__init__.py模块设置需要导入的Python标准库。

4.3.3模块导入总结

(1)同一模块,只会被导入一次。

(2)模块导入需要避免循环导入。

(3)使用import导入模块和导入包之间有很多差别。若是导入包,则只会导入包下的__init__.py模块。

(4)使用from...import *导入模块内的所有函数、变量和导入包下的所有模块有很大差别。若是导入包内部的所有模块,则必须在__init__.py模块中使用__all__。

4.4 dir()函数

4.4.1 dir()函数

dir()可以查看模块中中的定义(变量、函数、类),返回一个字符串列表。

# this is main.py

import sys

 

INFOS = dir(sys)

print(INFOS)

print(sys.argv)

在终端输入python .\main.py 123456,运行结果如下:

['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_enablelegacywindowsfsencoding', '_framework', '_getframe', '_git', '_home', '_xoptions', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', 'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth', 'get_coroutine_wrapper', 'getallocatedblocks', 'getcheckinterval', 'getdefaultencoding', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'getwindowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'set_coroutine_wrapper', 'setcheckinterval', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'version', 'version_info', 'warnoptions', 'winver']

['.\\main.py', '123456']

其中标准库sys中的argv参数是用来获取命令行参数。

当dir()函数内无任何参数时,会列出当前作用域中的定义。

# this is main.py

INFOS = dir()

print(INFOS)

运行结果:

['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']

__annotations__是内置函数,作用:函数注释。

__builtins__是对内置模块的引用。

在Python中有一个内置模块,其包含了很多Python常用的函数。因此在Python启动后且未执行任何代码之前,会加载该内置模块。在Python2.x中该内置模块命名被__builtin__;而在Python3.x中被重命名为builtins。

以Python3.x为例,当在主模块__main__中,__builtins__是对内置模块builtins的引用;在非__main__模块中,__builtins__是对__builtin__.__dict__的引用。

__cached__是内置变量,表示导入模块的缓存。

__doc__是内置变量,表示模块的注释。

__file__是内置变量,表示模块的路径。

__loader__是加载器在导入模块上设置的属性,访问它时将会返回加载器对象本身。

__name__是内置变量,表示模块的完整名称。若是入口文件,则表示主模块__main__。

__package__是内置变量,表示模块所属的包。

4.4.2常用的内置变量

在前面的dir()函数中,打印出内置变量__doc__、__file__、__name__、__package__。在这一节,通过代码来查看在主模块(入口文件)和普通模块中,这些内置变量的具体数值。

目录结构:

|--Python_Demo

|--pack1

p1_mod1.py

__init__.py

|--pack2

p2_mod1.py

__init__.py

mod1.py

run.py

'''this is run.py'''

import pack1.p1_mod1

 

print("__doc__      = %s"%__doc__)

print("__file__     = %s"%__file__)

print("__package__  = %s"%__package__)

print("__name__     = %s"%__name__)

'''this is p1_mod1.py'''

 

print("__doc__      = %s"%__doc__)

print("__file__     = %s"%__file__)

print("__package__  = %s"%__package__)

print("__name__     = %s"%__name__)

执行run.py的运行结果:

__doc__      = this is p1_mod1.py

__file__     = D:\Python\pack1\p1_mod1.py

__package__  = pack1

__name__     = pack1.p1_mod1

__doc__      = this is run.py

__file__     = .\run.py

__package__  = None

__name__     = __main__

可以看出在主模块(入口文件)中,其__name__是__main__。

4.4.3 __name__的用法

可以在py文件中使用if对__name__进行判断。若是__main__,则表示此模块是入口文件;否则表示这是一个普通模块。

'''this is run.py'''

 

if __name__ == "__main__":

    print('这是入口文件')

else:

    print('这是普通模块')

运行结果:

这是入口文件

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值