转: 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语句import file_name可以导入当前目录上file_name.py这个模块,但是里面的内容,必须通过file_name.func/file_name.var 来访问。 如果你一直在某个环境,比如解释器下面,你已经导入过某个模块 ,现在你对模块进行了修改,这里你需要用reload(modulename)来重新载入。 Python里,多次import的效果是只有第一次import有用,如果想要重新载入模块应该用reload(your_module)。 局部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_n 导入模块的两种方式的不同之处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的修改也不能反映到当前的代码. 包的两种导入模块或模块内函数的/变量的方式可能出现的错误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变量中给出的目录列表中查找。
Note: 从 * 导入包和__init__.py 中的__all__ 列表当用户写下 对于包的作者来说唯一的解决方案就是给提供一个明确的包索引。 import 语句按如下条件进行转换:执行
这意味着 如果没有定义 考虑以下代码:
在这个例子中,echo 和 surround 模块导入了当前的命名空间,这是因为执行 from...import 语句时它们已经定义在 sound.effects 包中了(定义了 尽管某些模块设计为使用 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一个模块查找偏好,而是一种约束(也就是说,一旦声明,必须是相对导入)
Python3绝对导入:按照sys.path顺序搜索,先主目录(sys.path中第一项''),然后PYTHONPATH环境变量、标准库路径、pth指定路径等。 包的相对导入import 语句总是绝对导入的, 所以相对导入只应用于 from-import 语句。 Python3相对导入:在模块所在同一个包内搜索,注意该包目录与主目录的区别。Python3中,每一个点号代替上一层目录。这样做的目的,主要是防止覆盖命名空间。 Note:从当前目录相对导入可以省略.号,不过不省略更好,以免之后修改系统不会自动调整(使用pycharm时,移动文件时,有.号它会自动修改导入路径)。 Example Phone/ __init__.py 在 Mobile.Analog.Digital , 也就是 Digital.py 模块中, 不能简单地使用错误语法(只能工作在旧版本的 Python 下, 在新的版本中它会导致一个警告, 或者干脆不能工作) 正确绝对导入方法: from Phone.Mobile.Analog import dial正确相对导入方法: 相对导入要注意的问题和常见错误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的 也就是使用
来区分包内和包外的运行测试。 [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 1.报错:ValueError: Attempted relative import beyond toplevel packages案例1: 目录树 所以使用相对导入的目录的平级目录内的所有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. 解决:将主程序移出到package外,如整个python目录NLP\TargetOpinion\***,TargetOpinion中的packages可以互相相对导入,但是TargetOpinion目录下不能有main模块,要移到外面,如NLP目录下,与TargetOpinion平齐。 当然这个案例就是将man.py放到case1平齐的目录中,如case1_1。 报错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: 目录树 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 下的两个目录中,有两个同名的软件包。你的子模块可能最终导入了另一个软件包,你将无意间使得某个或某些对此毫无戒备的程序员(或是你自己)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来导入模块。 让模块保持较小的规模你的模块应当比较小。记住,那个使用你软件包的程序员会在软件包作用域进行导入,同时你会使用你的 好的做法是一个模块只定义一个类,伴随一些帮助方法和工厂方法来协助建立这个模块。 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解释器把源代码转换成称为字节码的中间形式,然后再把它翻译成计算机使用的机器语言并运行。} 当你在下次从别的程序输入这个模块的时候, 模块内的所有定义dir() 函数当你为dir()提供一个模块名的时候,它返回模块定义的名称列表(函数、类和变量)。如果不提供参数,它返回当前模块中定义的名称列表(当前解释器中定义的命名)。
curModuleDir=dir() # get dir of current file(module)同时这句话放在模块(.py)文件函数或类外面 修改dir函数表现
def __dir__( self ): return [ 'area' , 'perimeter' , 'location' ] 模块的__name__属性 当一个模块被第一次输入import的时候,这个模块的主块将被运行。假如我们只想在程序本身被使用的时候运行主块,而在它被别的模块输入的时候不运行主块,这可以通过模块的__name__属性完成。 每个Python模块都有它的 from:http://blog.csdn.net/pipisorry/article/details/43313197 ref:简明python教程-模块和包 |
|