http://blog.csdn.net/pipisorry/article/details/43313197
模块和包
1. python程序由包(package)、模块(module)和函数组成。
2. 包是由一系列模块组成的集合。当不同作的模块进行按文件夹分类后再组成一个整体的库,可以称为包。为了让Python将目录当做内容包,目录中必须包含__init__.py文件,用于标识当前文件夹是一个包。最简单的情况下,只需要一个空的__init__.py文件即可。包就是一个完成特定任务的工具箱,包的作用是实现程序的重用。包导入会让模块扮演的角色更为明显,也使代码更具有可读性。
3. 模块是处理某一类问题的函数和类的集合,由代码、函数和类组成。函数是一段可以重复多次调用的代码。模块把一组相关的函数或代码组织到一个文件中,一个文件即是一个模块。每个模块文件是一个独立完备的命名空间,一个模块文件不能看到其他文件定义的变量名,除非它明确地导入了那个文件,模块文件起到了最小化命名冲突的作用。
python中引入包
两种导入语句
导入模块使用import和from语句(都是隐性的赋值语句),以及reload函数。可以导入模块名,还可以指定目录路径(Python代码的目录就称为包),包导入就是把计算机上的目录变成另一个Python命名空间,包的属性就是该目录包含的子目录和模块文件。当多个同名程序文件安装在某机器上时,包导入可以偶尔用来解决导入的不确定性。导入包也使用import和from语句。
import语句
python3引入同一目录下的py文件
注意:python2和python3的包内import语法有区别。
例如在admin.py文件中要引入dealcode.py文件:
1、在目录下有__init__.py文件
2、在admin.py文件中加一行:from . import dealcode
(如果要引入同一目录下的dealcode.py文件中的一个类Hello,在admin.py文件中加一行:from .dealcode import Hello)
可以直接在__init__.py中import,在该目录下的文件都可以使用__init__.py文件中import的东西
如果还是不行的话,注意一下当前目录是否已经被加入PYTHONPATH环境变量中了,
如果是命令行,系统会默认当前目录已经在环境变量中
python2引入同一目录下的py文件
import file_name可以导入当前目录上file_name.py这个模块,但是里面的内容,必须通过file_name.func/file_name.var 来访问。
如果你一直在某个环境,比如解释器下面,你已经导入过某个模块 ,现在你对模块进行了修改,这里你需要用reload modulename来重新载入。Python里,多次import的效果是只有第一次import有用,如果想要重新载入模块应该用reload。
局部import时还可以使用这种语法
__import__('shutil').rmtree(DATA_DIR)
subpackage导入时要这样:
__import__('geopy.distance').distance.vincenty(i, j).miles
相当于import geopy.distance; distance.vincenty(i, j).miles?
from import语句
另外一种导入方式为import func/var from file_name。这样func/var直接可用,但是file_name是没有定义的。
从file_name中导入所有:import * from file_name
。这样会导入所有除了以下划线开头的命名。实际代码中这样做往往是不被鼓励的。
导入模块的两种方式的不同之处
1. 与import类似, 被导入的module仍然会执行且仅执行一次
2. from *** import 的实质
当以 "from *** import " 方式导入module时, python会在当前module 的命名空间中新建相应的命名.
即, "from t2 import var1" 相当于:
import t2
var1= t2.var1
在此过程中有一个隐含的赋值的过程
由于python赋值操作特性(参考python变量名本质),在当前代码中对"var1"的修改并不能影响到t2.py中"var1"的值。同时,在t2.py中对var1的修改也不能反映到当前的代码。如果实在要改,可以这样:import t2; t2.var1 = something
包的两种导入模块或模块内函数的/变量的方式可能出现的错误
from package import item # 这种方式,item可以是包中的一个子模块或子包,也可以是包中定义的其他命名,像函数、类、变量。
import item.subitem.subsubitem # 这些子项必须是包,最后的子项是包或模块。但不能为函数、类或变量。否则出错:No module named ***
Note:
1. 陷阱:使用from导入变量,而那些变量碰巧和作用域中现有的变量同名,本地变量就会被悄悄地覆盖掉;使用import则没这个问题。
2.当b.py文件以from filename import fun方式从a.py文件引入函数fun时,如果有可执行语句在函数fun外,则引入后,执行b.py也会同时执行a.py在函数外的可执行语句,故一般不要把可执行脚本直接写到函数外,实在不想写入函数中也可以使用if __name__ == '__main__':...的方式。
模块的搜索路径
首先会搜索解析器的当前目录。然后会到sys.path变量中给出的目录列表中查找。
>>> import sys
>>> sys.path
['', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']
- 输入脚 本的目录(当前目录)
- 环境变量
PYTHONPATH
表示的目录列表中搜索 - Ptyon的默认安装路径中搜索。
Note:sys.path
包含输入模块的目录名列表。我们可以观察到sys.path
的第一个字符串是空的——这个空的字符串表示当前目录也是sys.path
的一部分,这与PYTHONPATH
环境变量是相同的。这意味着你可以直接输入位于当前目录的模块。否则,你得把你的模块放在sys.path
所列的目录之一。[python系统模块sys、os和路径、系统命令]
从 * 导入包和__init__.py 中的__all__ 列表
当用户写下 from sound.Effects import *
时会发生什么事?理想中,总是希望在文件系统中找出包中所有的子模块,然后导入它们。这可能会花掉很有长时间,并且出现期待之外的边界效应,导出了希望只能显式导入的包。
对于包的作者来说唯一的解决方案就是给提供一个明确的包索引。
import 语句按如下条件进行转换:
执行 from package import *
时,如果包中的__init__.py
代码定义了一个名为__all__
的列表,就会按照列表中给出的模块名进行导入。新版本的包发布时作者可以任意更新这个列表。如果包作者不想 import * 的时候导入他们的包中所有模块,那么也可能会决定不支持它( import * )。例如,sounds/effects/__init__.py
这个文件可能包括如下代码:
__all__ = ["echo", "surround", "reverse"]
这意味着 from Sound.Effects import *
语句会从 sound 包中导入以上三个已命名的子模块。
如果没有定义 __all__
, from Sound.Effects import *
语句 不会 从 sound.effects 包中导入所有的子模块。无论包中定义多少命名,只能确定的是导入了 sound.effects 包(可能会运行__init__.py
中的初始化代码)以及包中定义的所有命名会随之导入。这样就从__init__.py
中导入了每一个命名(以及明确导入的子模块)。同样也包括了前述的 import 语句从包中明确导入的子模块。
考虑以下代码:
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
在这个例子中,echo 和 surround 模块导入了当前的命名空间,这是因为执行 from...import 语句时它们已经定义在 sound.effects 包中了(定义了__all__
时也会同样工作)。
尽管某些模块设计为使用 import * 时它只导出符全某种模式的命名,仍然不建议在生产代码中使用这种写法。
记住,from Package import specific_submodule 没有错误!事实上,除非导入的模块需要使用其它包中的同名子模块,否则这是推荐的写法。
包的绝对导入和相对导入
python 2.7及之前版本
中默认是先“相对”后“绝对”的顺序搜索模块,也就是说先在模块所在同一个包内搜索然后在sys.path中搜索。为此,所有的导入现在都被认为是绝对的, 也就是说这些名字必须通过 Python 路径(sys.path 或是 PYTHONPATH )来访问。python 2.x在包内模块的导入,顺序是:
1、当前目录
2、上一个目录
3、找不到再往上
4、系统环境变量
5、标准库
6、前三个在搜索路径下的 .pth文件
Python 2.7之后版本
包的绝对导入
很多情况下导入子包会导致和真正的标准库模块发生(事实上是它们的名字)冲突。 包模块会把名字相同的标准库模块隐藏掉, 因为它首先在包内执行相对导入, 隐藏掉标准库模块。
从 Python 2.7 开始默认绝对导入。 python3.x 中的包内的模块导入原则编程了:如果要相对导入,那么一定是显式声明,并且,这个声明不是告诉python一个模块查找偏好,而是一种约束(也就是说,一旦声明,必须是相对导入)
from __future__ import absolute_import
: 在 3.0 以前的旧版本中启用相对导入等特性所必须的 future 语句。
Python3绝对导入:按照sys.path顺序搜索,先主目录(sys.path中第一项''),然后PYTHONPATH环境变量、标准库路径、pth指定路径等。
包的相对导入
import 语句总是绝对导入的, 所以相对导入只应用于 from-import 语句。
Python3相对导入:在模块所在同一个包内搜索,注意该包目录与主目录的区别。Python3中,每一个点号代替上一层目录。这样做的目的,主要是防止覆盖命名空间。
Note:从当前目录相对导入可以省略.号,不过不省略更好,以免之后修改系统不会自动调整(使用pycharm时,移动文件时,有.号它会自动修改导入路径)。
Example
Phone/
__init__.py
common_util.py #其中包含setup
Fax/
__init__.py
G3.py #其中包含dial
Mobile/
__init__.py
Analog.py #其中包含dial
Digital.py
在 Mobile.Analog.Digital , 也就是 Digital.py 模块中, 不能简单地使用错误语法(只能工作在旧版本的 Python 下, 在新的版本中它会导致一个警告, 或者干脆不能工作)
import Analog
from Analog import dial
正确绝对导入方法:
from Phone.Mobile.Analog import dial
正确相对导入方法:
from .Analog import dial # . 代表当前.py文件所在目录Mobile/
from ..common_util import setup
from ..Fax import G3.dial.
[Python核心编程2ed]
相对导入要注意的问题和常见错误
lz总结的一个模块导入法则:Use relative import only in modules and run the scripts outside the package. 也就是说使用相对导入的文件不应该是要运行执行的文件,而应该只是外层调用的模块。但是如果你非要在packges里面做测试的话,那就不要使用相对导入。Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.[documentation]
终极解决方案
import sys
import os
#将mymodule模块(目录)所在的目录(如这个py文件的../..)加入到pythonpath中就可以使用from mymodule import *了
sys.path.append(os.path.join(os.path.split(os.path.realpath(__file__))[0],"../.."))
try:
from .mymodule import myclass
except Exception: #ImportError
from mymodule import myclass
示例
Note: 最顶层的SocialNetworks是一个单纯的目录,而下层的SocialNetworks开始就是一个python package.
运行MainTest.py,EBM中导入的就是try中的import
直接运行EBM.py,是从except中import的
也就是使用
try:
from .mymodule import myclass
except Exception: #ImportError
from mymodule import myclass
来区分包内和包外的运行测试。
[SystemError: Parent module '' not loaded, cannot perform relative import]
后来lz发现pycharm中不用加入路径就可以导入except中的语句,from SocialNetworks.SocialNetworks引入成功的原因是lz在pycharm中添加了add content roots to pythonpath了,这样sys.path中多了一个整个项目project的路径/media/pika/files/mine/python_workspace,里面的目录就被当成包使用,所以可以引入成功!在代码中加入路径后,在pycharm之外也可以正常运行from SocialNetworks.SocialNetworks了,所以lz建议关闭pycharm的add roots to pythonpath这种功能。
[Why does PyCharm always add “contents root” to my PYTHONPATH, and what PYTHONPATH?]
下面这几个错误好像都可以使用上述的方法解决,下面是以前总结的解决方案,不怎么好。
python拓展包的调用
>>> import sys
>>> sys.path
['', '/home/pipi/ENV/ubuntu_env/lib/python35.zip', '/home/pipi/ENV/ubuntu_env/lib/python3.5', '/home/pipi/ENV/ubuntu_env/lib/python3.5/plat-x86_64-linux-gnu', '/home/pipi/ENV/ubuntu_env/lib/python3.5/lib-dynload', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/home/pipi/ENV/ubuntu_env/lib/python3.5/site-packages']
可以看到/home/pipi/ENV/ubuntu_env/lib/python3.5/site-packages在sys.path中,所以可以在python中调用这些不同的拓展包(如使用pip安装的包)。
1.报错:ValueError: Attempted relative import beyond toplevel packages
案例1:
目录树
case1/
├── cat
│ ├── __init__.py
│ ├── cat.py
├── dog
│ ├── __init__.py
│ └── dog.py
├── __init__.py
└── main.py
代码
# case1/cat/cat.py
from .. import dog
# case1/main.py
import cat.cat
执行
python case1/main.py
错误原因:
这里的 case1 是一个包,但当你直接执行 main.py 的时候,就没有把完整的 case1 当作一个包来处理了( the package should be entirely self contained. It won't treat case1/ as a package when you're running main.py inside it.),而cat和dog还是包,并且已经是包树的顶层了。可想而知,下层的 cat.py (import cat.cat)自然找不到上层包了,想要相对导入成功,必须让下层的被导入对象是上层包或上层包内的对象。
所以使用相对导入的目录的平级目录内的所有py文件不允许单独执行(当然局部测试时是可以的,而不是将包中的py文件当作主应用程序执行),要保证这个模块不是入口文件(py文件中有if __name__ == '__main__',其实也不一定有这个,只要你执行就算是),只是作为被导入的模块才可以以这样使用。
python 中只能在package中使用相对导入,不能在用户的应用程序中使用相对导入,因为不论是相对导入还是绝对导入,都是相当于当前模块来说的,对于用户的主应用程序,也就是入口文件,模块名总是为“ __main__ ”, 所以用户的应用程序(如NLP目录下有一个main.py[包含__main__],要执行的)必须使用绝对导入,而package(如__main__调用的包NLP\TargetOpinion)中的导入可以使用相对导入。
When launching a python source file, it is forbidden to import another file, that is in the current package, using relative import.
解决:
1 假设整个项目目录NLP\TargetOpinion\***;将主程序移出到package(即TargetOpinion\***)外,TargetOpinion中的子packages可以互相相对导入,但是package即TargetOpinion目录下不能有main模块,要移到外面,如NLP目录下,与TargetOpinion平齐。
当然上面案例就是将main.py放到case1平齐的目录中,如case1_1。
2 如果main.py想放到与TargetOpinion平齐的目录中,如NLP\test,这时也不能使用..TargetOpinion来调用,但是可以先将NLP目录加入path:sys.path.append(os.path.join(os.path.split(os.path.realpath(__file__))[0], "..")),再使用TargetOpinion来调用。
报错2:SystemError: Parent module '' not loaded, cannot perform relative import?
这种情况一般是因为case1不是包(目录下没有__init__),而 cat.cat.py要调用dog.dog.py(from ..dog import dog),这样上层..不是包不能导入出错。
不过在pycharm中设置source root(或者加入../..到sys.path中)好像也可以解决。
案例2:
目录树
case3/
├── alpaca.py
├── main.py
└── pets
├── __init__.py
├── cat
│ ├── __init__.py
│ └── cat.py
└── dog
├── __init__.py
└── dog.py
代码
# case3/pets/cat/cat.py
from ..dog import dog
from .. import dog
# case3/main.py
from pets.cat import cat
执行
python case3/main.py
请注意,这里的 cat.py 中是不能导入 alpaca 的,因为 pets 已经是这个包树的顶层了(case3中包含main.py其中包含main函数,这样case3就不会被当作包?)。
2.ImportError: No module named '***'
sys.path没有加入导入的模块所在目录
3.忌两个py文件循环导入
4. 使用相对导入非本级目录的py也禁止单独运行
否则报错: ValueError: Attempted relative import in non-package
[python package module import 完全总结]
在软件包内部只进行相对导入
在子模块中你时常见到的一个简单错误,就是使用软件包的名字来导入软件包。
# within a sub-module
from
a_package
import
APackageError
这样做会导致两个不好的结果:
- 子模块只有当软件包被安装在 PYTHONPATH 内才能正确运行。
- 子模块只有当这个软件包的名字是 a_package 时才能正确运行。
尽管第一条看上去并不是什么大问题,但是考虑一下,如果你在 PYTHONPATH 下的两个目录中,有两个同名的软件包。你的子模块可能最终导入了另一个软件包,你将无意间使得某个或某些对此毫无戒备的程序员(或是你自己)debug 到深夜。
所以说,在软件包中最好只进行相对导入,而运行的执行文件(__main__)都放在软件包外面。
AttributeError: 'module' object has no attribute '***'
如import scipy或者import dateutil后
使用scipy.misc或者dateutil.parser出错
原因:because the parser.py is a module in the dateutil package. It's a separate file in the folder structure.所以要手动添加。其实主要是ubuntu_env/lib/python3.5/site-packages/dateutil$ vi __init__.py中没有from . import subpackages,自己修改一下就好了,不过它本身没这么加肯定有它的原因,lz暂时还没搞清楚。
解决:所以最好还是使用import dateutil.parser或者from dateutil import parser来导入模块。
让模块保持较小的规模
你的模块应当比较小。记住,那个使用你软件包的程序员会在软件包作用域进行导入,同时你会使用你的 __init__.py
文件来作为一个组织工具,来暴露一个完整的接口。
好的做法是一个模块只定义一个类,伴随一些帮助方法和工厂方法来协助建立这个模块。
class
APackageClass(
object
):
'''One class'''
def
apackage_builder(how_many):
for
i
in
range
(how_many):
yield
APackageClass()
如果你的模块暴露了一些方法,把一些相互依赖的方法分为一组放进一个模块,并且把不相互依赖的方法移动到单独的模块中,一个例子是 fsq/enqueue.py,它暴露了一系列的方法来为同一个功能提供不同的接口(就像 simplejson 中的l oad/loads)。尽管这个例子足够直观,让你的模块保持较小规模需要一些判断,但是一个好的原则是:当你有疑问的时候,就去创建一个新的子模块吧。
字节编译文件.pyc
输入一个模块相对来说是一个比较费时的事情,所以Python做了一些技巧,以便使输入模块更加快一些。
一种方法是创建 字节编译的文件 ,这些文件以.pyc作为扩展名。字节编译的文件与Python变换程序的中间状态有关。{一个用编译性语言比如C或C++写的程序可以从源文件(即C或C++语言)转换到一个你的计算机使用的语言(二进制代码,即0和1)。这个过程通过编译器和不同的标记、选项完成。当你运行你的程序的时候,连接/转载器软件把你的程序从硬盘复制到内存中并且运行。而Python语言写的程序不需要编译成二进制代码。你可以直接从源代码运行 程序。在计算机内部,Python解释器把源代码转换成称为字节码的中间形式,然后再把它翻译成计算机使用的机器语言并运行。}
当你在下次从别的程序输入这个模块的时候,.pyc
文件是十分有用的——它会快得多,因为一部分输入模块所需的处理已经完成了。另外,这些字节编译的文件也是与平台无关的。
模块内的所有定义
dir()
函数
当你为dir()提供一个模块名的时候,它返回模块定义的名称列表(函数、类和变量)。如果不提供参数,它返回当前模块中定义的名称列表(当前解释器中定义的命名)。
>>> import fibo
>>> dir(fibo)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'fib', 'fib2']
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'fibo']
dir()
并不会列出内置函数和变量名。如果你想列出这些内容,它们在标准模块__builtin__
中定义。
curModuleDir=dir() # get dir of current file(module)同时这句话放在模块(.py)文件函数或类外面
修改dir函数表现
class
Shape(
object
):
def
__dir__(
self
):
return
[
'area'
,
'perimeter'
,
'location'
]
则返回指定的三个函数字符串
模块的__name__属性
当一个模块被第一次输入import的时候,这个模块的主块将被运行。假如我们只想在程序本身被使用的时候运行主块,而在它被别的模块输入的时候不运行主块,这可以通过模块的__name__属性完成。
每个Python模块都有它的__name__
,如果它是'__main__'
,这说明这个模块被用户单独运行,我们可以进行相应的恰当操作。
Import成功但是pycharm中无法点击进入
使用torch.utils.data.DataLoader时,pycharm中无法直接点击进入代码。
torch.utils Cannot find reference 'utils' in '__init__.pyi
可以通过更新torch到1.6.0解决,但是会出另一个问题:Cannot find reference 'data' in '__init__.pyi
解决方法:同时
import torch
import torch.utils.data #这样就可以了
from:python模块导入及属性:import_python 为模块增添属性_-柚子皮-的博客-CSDN博客
ref:简明python教程-模块和包