模块和包

 一.模块

   1.什么是模块

  一个模块就是包含了python 定义和声明的文件,文件名就是模块名加.py后缀

  2.模块的作用

  方便管理,使功能得到重复利用

  3.使用模块

      3.1 模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行,第一次导入后就已将模块名加载到内存中了。

   3.2 每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当作全局名称空间,编写自己的模块时不用担心与使用者的全局变量发生冲突。

      3.3 首次导入模块my_moudle时会做三件事:

   1.为源文件(my_moudle模块)创建新的名称空间,在my_moudle中定义的函数和方法若是使用到了global时访问的就是这个名称空间。

   2.在新创建的命名空间中执行模块中包含的代码,见初始导入import my_moudle

   3.创建名字my_moudle来引用该命名空间

   3.4 为模块起名 

#import my_module as sm
#print(sm.money)

   3.5 在一行中导入多个模块

#import sys,os,re

   3.6 from...import

#from my_module import read1,read2
#这样可以直接用模块中的名字
#如果当前文件中有和module中一样的名字比如都有read(),则会被覆盖

  注意:python中的变量赋值不是一种存储操作,而只是一种绑定关系

#from my_moudle import money,read1
#money=100 #将当前位置的名字money绑定到了100
#print(money) #打印当前的名字
#read1() #读取my_moudle.py中的名字money,仍然为1000

'''
#from the my_moudle.py
#my_moudle->read1->money 1000
'''

   3.7 支持as,也支持多行导入

# from my_moudle import read1 as read

# from my_moudle import (read1,
#                 read2,
#                   money)

  3.8 from my_moudle import * 把my_moudle中所有的不是以下划线(_)开头的名字都导入到当前位置,大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题。

#from my_moudle import * #将模块my_moudle中所有的名字都导入到当前名称空间
#print(money)
#print(read1)
#print(read2)
#print(change)


#执行结果:
#from the my_moudle.py
#<function read1 at 0x1012e8158>
#<function read2 at 0x1012e81e0>
#<function change at 0x1012e8268>
#在my_moudle.py中新增一行

#__all__=['money','read1'] 
#这样在另外一个文件中用from my_moudle import *就这能导入列表中规定的两个名字

  3.9考虑到性能的原因,每个模块只被导入一次,放入字典sys.module中,如果你改变了模块的内容,你必须重启程序,python不支持重新加载或卸载之前导入的模块

#def func1():
#    print('func1')

#import time,importlib
#import aa
 
#time.sleep(20)
   # importlib.reload(aa) #ctrl + s 可以更改
#aa.func1()

  4.0把模块当作脚本执行

  我们可以通过模块的全局变量__name__来查看模块名:
  当做脚本运行:
  __name__ 等于'__main__'

  当做模块导入:
  __name__= 模块名

  作用:用来控制.py文件在不同的应用场景下执行不同的逻辑
  if __name__ == '__main__':

def fib(n):   
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
    print()

if __name__ == "__main__":
    print(__name__)
    num = input('num :')
    fib(int(num))

  4.1 模块搜索路径

   内存中已经加载的模块->内置模块->sys.path路径中包含的模块

   4.2 编译python文件

  为了提高模块的的加载速度,python解释器会在__pycache__目录中下缓存每个模块编译后的版本,格式为:module.version.pyc。通常会包含python的版本号。例如,在CPython3.3版本下,my_moudle.py模块会被缓存成__pycache__/my_moudle.cpython-33.pyc。这种命名规范保证了编译后的结果多版本共存。

二.包

   2.1

  1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法

  2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)

  3. import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件

  强调:

  1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错

  2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块

  2.2

  注意:

     1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。

     2.对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。

     3.对比import item 和from item import name的应用场景:
    如果我们想直接使用name那必须使用后者。

   2.3 from ..import ...

 需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法

  2.4 __init__.py文件

   不管是哪种方式,只要是第一次导入包或者是包的任何其他部分,都会依次执行包下的__init__.py文件(我们可以在每个包的文件内都打印一行内容来验证一下),这个文件可以为空,但是也可以存放一些初始化包的代码。

原文地址:https://www.cnblogs.com/sxh-myblogs/p/7327238.html