bin.py是主执行文件,所以执行时python只会把他的目录binDir/加入到环境变量sys.path中,导入是否成功只能看被导入的包路径是否在binDir/下,显然是找不到all/m.py的,要想找到m.p y,必须要把all的目录“模块&包&导入”加入到sys.path
# bin.py
import os, sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# 然后再导入:注意使用from XX.sd import XX时,把我一个原则,from的.左边必须是包,import的XX可以是文件,类,变量
from all import m
2.在第一步的基础上如果m.py中又有导入import cal的操作,还是会报错,找不到cal模块
原因:from all import m时会加载并执行m.py中的顶层代码,即会把import cal加载到主执行文件bin.py执行,虽然第一步把“模块&包&导入”加入到了sys.path环境变量中了,但是也不能这样直接导入,在m.py文件中将导入方式修改成在主执行文件中可见的方式:from all import cal即可解决
3.动态导入
(1)格式
# 格式:导入字符串格式的模块module1
m = __import__("module1")
print(m) #
(2)注意:
无论module1.t1.t2路径有多深,m始终是顶级模块module1,要想调用下面的t1之类的需要手动调用:m.t1或m.t1.t2
m = __import__("module1.t1.t2") #m是module1
importlib模块可以解决上面问题
import importlib
m = importlib.import_module("module1.t1.t2") #m是module1.t1.t2
1.定义 包是一种通过使用‘.模块名’来组织python模块名称空间的方式。 无论是import形式还是from…import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法。.的左边必须是包。简单来说,包就是文件夹,但该文件夹下必须存在
init.py 文件, 该文件的内容可以为空。int.py用于标识当前文件夹是一个包。 包是由一系列模块组成的集合。模块是处理某一类问题的函数和类的集合。
2.import
在使用一个模块中的函数或类之前,首先要导入该模块。模块的导入使用import语句。
调用模块的函数或类时,需要以模块名作为前缀。
import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
凡是在导入时带点的,点的左边都必须是一个包。
3.from … import …
如果不想在程序中使用前缀符,可以使用from…import…语句将模块导入。
需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法
注意:
(1).关于包相关的导入语句也分为import和from … import …两种,但是无论哪种,无论在什么位置,在导入时都必须遵循两个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则;from … import 后面不能再有点了
注意:from import的import后面只能跟py模块文件、函数、变量,不能跟包名,所以也就不能带点了,只有包名后面才能带点,所以import后面不能接包名同时也不会有点存在了
(2).对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
(3).对比import item 和from item import name的应用场景:
如果我们想直接使用name那必须使用后者。
(4).init.py文件
不管是哪种方式,只要是第一次导入包或者是包的任何其他部分,都会依次执行包下的__init__.py文件(我们可以在每个包的文件内都打印一行内容来验证一下),这个文件可以为空,但是也可以存放一些初始化包的代码。
5.from … import *
从包api中导入所有,实际上该语句只会导入包api下__init__.py文件中定义的名字,我们可以在这个文件中定义__all___:
如果是文件,就导入文件中定义的__all__列表中的变量、函数等
(6).多个文件相互导入,要注意python默认只是将执行主文件所在的目录加入到sys.path列表,要注意路径,或者使用相对路径
(7).单独导入包
单独导入包名称时不会导入包中所有包含的所有子模块,如
#在与glance同级的test.py中
import glance
glance.cmd.manage.main()
会报错,因为,只能找到glance,解决方法是:(manage是文件,packageTools、cmd是包)
1)import packageTools.cmd.manage
packageTools.cmd.manage.main()
2)from packageTools.cmd import manage
manage.main()
3)from packageTools.cmd.manage import main
main()
4)from packageTools import cmd
cmd.manage.main()
#import 包名时,要在cmd对应的init文件里加上from . import manage才可以:import 包名,是执行包下的init文件,但是如果init文件为空时,你也拿不到manage模块
上面两种都是直接拿到manage.py或者其中的main函数了,所以可以直接执行,所以要想使用需要在相应的init中连接上manage.py或者main,所以上面的导入不会报错,只有cmd.manage时报cmd没有manage属性的错误,所以要在cmd的init文件加上:from . import manage之后,cmd.manage才不会报错
同理:import packageTools
packageTools.cmd.manage.main()
也是执行packageTools下的init文件,所以也会报错,除非在packageTools、cmd的init中链接上相应路径
import packageTools.cmd.manage或者import packageTools.cmd.manage.main()就不会报错
而from packageTools.cmd.manage import main
,from packageTools.cmd import manage,是因为from后面的import只能导入模块(相应from到最后一个包)或者函数(相应from到模块),如果from 后面的import导入的是包,那from是上一层的包,但是from后包的相应的init中要加上到模块的链接才可以二、import本质如下:
1、import module:解释该module中的.py文件,并赋值给module名
2、import package:执行该package中_init_文件
注意:from import的import后面只能跟py文件,或者函数,不能跟包,所以也就不能带点了
(4)#packageTools/init.py from . import cmd#packageTools/cmd/init.py from . import manage
import packageTools packageTools.cmd.manage.main()
二、import本质
1、import module:解释该module中的.py文件,并赋值给module名
2、import package:执行该package中_init_文件
在python模块的每一个包中,都有一个__init__.py文件(这个文件定义了包的属性和方法)然后是一些模块文件和子目录,假如子目录中也有__init__.py
那么它就是这个包的子包了。当你将一个包作为模块导入(比如从 xml 导入 dom )的时候,实际上导入了它的__init__.py 文件。一个包是一个带有特殊文件 init.py 的目录。init.py
文件定义了包的属性和方法。其实它可以什么也不定义;可以只是一个空文件,但是必须存在。如果 init.py
不存在,这个目录就仅仅是一个目录,而不是一个包,它就不能被导入或者包含其它的模块和嵌套包。我们有时会使出一招“全部导入”,也就是这样: from lib import * 1 这时 import
就会把注册在包__init__.py 文件中 all 列表中的子模块和子包导入到当前作用域中来。比如:#文件__init__.py
all = [“mod2”, “mod3”, “sub”]
这种做法在少数情况下是挺方便的,但是这样也会打乱你的命名空间。问题在于,你可能定义了一个与导入模块中名称相同的变量或函数,这时如果你试图使用os模块中的同名变量或函数,实际使用的将是你自己定义的内容。因此,你最后可能会碰到一个相当让人困惑的逻辑错误。标准库中我唯一推荐全盘导入的模块只有Tkinter
如果你正好要写自己的模块或包,有人会建议你在init.py文件中导入所有内容,让模块或者包使用起来更方便。我个人更喜欢显示地导入,而非隐式地导入。
你也可以采取折中方案,从一个包中导入多个项:
from os import path, walk, unlink from os import uname, remove
在上述代码中,我们从os模块中导入了5个函数。你可能注意到了,我们是通过多次从同一个模块中导入实现的。当然,如果你愿意的话,你也可以使用圆括号一次性导入多个项:
from os import (path, walk, unlink, uname,
remove, rename)这是一个有用的技巧,不过你也可以换一种方式:
from os import path, walk, unlink, uname,
remove, rename上面的反斜杠是Python中的续行符,告诉解释器这行代码延续至下一行。
4.可选导入(Optional imports)
try:
#python2
from urlparse import urljoin
from urllib2 import urlopen except ImportError:
# Python 3
from urllib.parse import urljoin
from urllib.request import urlopen5.局部导入
当你在局部作用域中导入模块时,你执行的就是局部导入。如果你在Python脚本文件的顶部导入一个模块,那么你就是在将该模块导入至全局作用域,这意味着之后的任何函数或方法都可能访问该模块。例如:
import sys # global scope
def square_root(a):
# This import is into the square_root functions local scope
import math
return math.sqrt(a)def my_pow(base_num, power):
return math.pow(base_num, power)if name == ‘main’:
print(square_root(49))
print(my_pow(2, 3))这里,我们将sys模块导入至全局作用域,但我们并没有使用这个模块。然后,在square_root函数中,我们将math模块导入至该函数的局部作用域,这意味着math模块只能在square_root函数内部使用。如果我们试图在my_pow函数中使用math,会引发NameError。试着执行这个脚本,看看会发生什么。
使用局部作用域的好处之一,是你使用的模块可能需要很长时间才能导入,如果是这样的话,将其放在某个不经常调用的函数中或许更加合理,而不是直接在全局作用域中导入。老实说,我几乎从没有使用过局部导入,主要是因为如果模块内部到处都有导入语句,会很难分辨出这样做的原因和用途。根据约定,所有的导入语句都应该位于模块的顶部。