模块

模块

什么是模块?
模块就是一个功能的集合体,不是用来直接运行,而是用来被导入使用的

模块分为三大来源:
  1,内置的模块
  2,第三方模块
  3,自定义的模块
模块分为四种类别:

1,一个py文件就是一个模块
2,一个文件夹也是一个模块=>包
3,已被编译为共享库或dll的c或c++扩展
4,使用c编写并链接到python解释器的内置模块

为何要用模块

使用别人的模块:
1,拿来主义,提升开发效率
自定义模块:
1,别人的功能不够用了,需要自己的去编写
2,解决代码冗余

3,如何用模块

导入模块时会发生的三件事

文件名是spam.py,模块名则是spam

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

2.在新创建的命名空间中执行模块中包含的代码,见初始导入import spam
提示:导入模块时到底执行了什么?
In fact function definitions are also ‘statements’ that are
‘executed’; the execution of a module-level function definition
enters the function name in the module’s global symbol table.
事实上函数定义也是“被执行”的语句,模块级别函数定义的执行将函数名放
入模块全局名称空间表,用globals()可以查看

3.创建名字spam来引用该命名空间
这个名字和变量名没什么区别,都是‘第一类的’,且使用spam.名字的方式
可以访问spam.py文件中定义的名字,spam.名字与test.py中的名字来自
两个完全不同的地方。

import...
import spam
import spam
import sram

money = 2000

print(money)
print(spam.money)
spam.read1()
def read1():
   print('run1.py-----read1')

spam.read2()
spam.change()
print(spam.money)
print(money)

一行导入多个模块
import spam,m1,m2,m3 # 不推荐

被导入的模块有独立的名称空间

每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会在被导入时,与使用者的全局变量冲突

为导入的模块起别名

import spamasdfdsfssdfsfeer as sb
sb.xxx

示例:


def sqlparse():
   print('from mysql sqlparse')
def sqlparse():
   print('from oracle sqlparse')

db_type = input('>>>>:')
if db_type == 'mysql':
   import mysql as db
elif db_type == 'oracle':
   import oracle as db

db.sqlparse()

文件名是spam.py,模块名则是spam
x=111
from spam import money,read1,read2  # money=spam.money,read1=spam.read1,read2=spam.read2
from...import
   money=模块spam中的money对应值的内存地址
   read1=模块spam中的read1对应值的内存地址
   read2=模块spam中的read2对应值的内存地址


from spam import money,read1,read2
from spam import money,read1,read2
from spam import money,read1,read2
from spam import money,read1,read2

print(money)
print(read1)
print(read2)


money=111
print(money)

money=2000
read1()

def read1():
    print('run.py read1')
read2()

当前位置直接使用read1和read2就好了,执行时,仍然以spam.py文件全局名称空间

测试一:导入的函数read1,执行时仍然回到spam.py中寻找全局变量money
#test.py
from spam import read1
money=1000
read1()
'''
执行结果:
from the spam.py
spam->read1->money 1000
'''

测试二:导入的函数read2,执行时需要调用read1(),仍然回到spam.py中找read1()
#test.py
from spam import read2
def read1():
    print('==========')
read2()

'''
执行结果:
from the spam.py
spam->read2 calling read
spam->read1->money 1000
'''

如果当前有重名read1或者read2,那么会有覆盖效果

#测试三:导入的函数read1,被当前位置定义的read1覆盖掉了
#test.py
from spam import read1
def read1():
    print('==========')
read1()
'''
执行结果:

from the spam.py
==========

'''
一行导入多个名字
from spam import money,read1
为导入的模块起别名

from spam import money as m

print(m)

from...import *

#from spam import * 把spam中所有的不是以下划线(_)开头的名字都导入到当前位置

#大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题
from spam import *
from spam import *
print(money)
print(read1)
print(read2)
print(change)
可以使用__all__来控制*(用来发布新版本),在spam.py中新增一行
__all__=['money','read1'] #这样在另外一个文件中用from spam import *就这能导入列表中规定的两个名字

from...import 与 import的对比

唯一的区别就是:使用from...import...则是将spam中的名字直接导入到当前的名称空间中,所以在当前名称空间中,直接使用名字就可以了、无需加前缀:spam.

from...import...的方式有好处也有坏处
    好处:使用起来方便了
    坏处:容易与当前执行文件中的名字冲突
模块循环导入的问题

模块循环导入抛出异常的根本原因是由于在python中模块被导入一次之后,就不会重新导入,

只会在第一次导入时执行模块内代码,如果出现多个模块都需要共享的数据,可以将共享的数据集中存在摸一个地方

#示范文件内容如下
#m1.py
print('正在导入m1')
from m2 import y

x='m1'

#m2.py
print('正在导入m2')
from m1 import x

y='m2'

#run.py
import m1

#测试一
执行run.py会抛出异常
正在导入m1
正在导入m2
Traceback (most recent call last):
  File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/aa.py", line 1, in <module>
    import m1
  File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m1.py", line 2, in <module>
    from m2 import y
  File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m2.py", line 2, in <module>
    from m1 import x
ImportError: cannot import name 'x'

#测试一结果分析
先执行run.py--->执行import m1,开始导入m1并运行其内部代码--->打印内容"正在导入m1"
--->执行from m2 import y 开始导入m2并运行其内部代码--->打印内容“正在导入m2”--->执行from m1 import x,由于m1已经被导入过了,所以不会重新导入,所以直接去m1中拿x,然而x此时并没有存在于m1中,所以报错


#测试二:执行文件不等于导入文件,比如执行m1.py不等于导入了m1
直接执行m1.py抛出异常
正在导入m1
正在导入m2
正在导入m1
Traceback (most recent call last):
  File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m1.py", line 2, in <module>
    from m2 import y
  File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m2.py", line 2, in <module>
    from m1 import x
  File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m1.py", line 2, in <module>
    from m2 import y
ImportError: cannot import name 'y'


#测试二分析
执行m1.py,打印“正在导入m1”,执行from m2 import y ,导入m2进而执行m2.py内部代码--->打印"正在导入m2",执行from m1 import x,此时m1是第一次被导入,执行m1.py并不等于导入了m1,于是开始导入m1并执行其内部代码--->打印"正在导入m1",执行from m1 import y,由于m1已经被导入过了,所以无需继续导入而直接问m2要y,然而y此时并没有存在于m2中所以报错



# 解决方法:

方法一:导入语句放到最后
#m1.py
print('正在导入m1')

x='m1'

from m2 import y

#m2.py
print('正在导入m2')
y='m2'

from m1 import x

方法二:导入语句放到函数中
#m1.py
print('正在导入m1')

def f1():
    from m2 import y
    print(x,y)

x = 'm1'

# f1()

#m2.py
print('正在导入m2')

def f2():
    from m1 import x
    print(x,y)

y = 'm2'

#run.py
import m1

m1.f1()


py文件区分两种用途

编写好的一个python文件可以有两种用途:
一:脚本,一个文件就是整个程序,用来被执行
二:模块,文件中存放着一堆功能,用来被导入使用

python为我们内置了全局变量__name__,
当文件被当做脚本执行时:name 等于'main'
当文件被当做模块导入时:__name__等于模块名

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

模块的搜索路径与查找优先级
1,先从内存中已经导入的模块里找

import mmm

mmm.f1()

import time

time.sleep(15)

print("="*50)

import mmm

mmm.f1

2,然后在查找内置的模块

import sys

print(sys.modules)



import sys

print(sys.path)

当前 执行文件所在的文件夹

import logging

print(logging)

最后去sys.path列表中存放的多个文件夹里依次检索

示例1:

import sys

print(sys.path)

sys.path.append(r'D:python全栈15期aaabb')

import ccc

ccc.f1()

示例2:

import sys

print(sys.path)

import aaa.bbb.ccc as c

c.f1()
原文地址:https://www.cnblogs.com/lgh8023/p/13369228.html