• 1. Python程序设计 Programming in Python主讲:庞胜利
  • 2. 2第六章 模块模块介绍 为什么使用模块 Python程序架构 创建模块 模块导入 Python命名空间 作用域 模块重载入 包
  • 3. 模块简介模块是最高级别的程序组织单元,它将程序代码和数据封装起来以便重用。 从实际角度看,Python的模块一般对应于程序文件(py文件),每个文件都是一个模块,而且模块导入其他模块之后就可以使用导入模块定义的变量名。
  • 4. 模块简介模块可以由两个语句和一个重要的内置函数进行处理 import 使客户端(导入者)以一个整体获取一个模块 from 允许客户端从一个模块文件中获取特定的变量名 reload 在不终止Python程序情况下,提供一种重新载入模块文件代码的方法
  • 5. 为什么使用模块简而言之,模块通过使用自包含的变量的包,也就是命名空间提供了将部件组织为系统的简单的方法 在一个模块文件的顶层定义的所有变量名都成为被导入的模块对象的属性 也就是说,在模块导入时,模块文件的全局作用域变成了模块对象的对象命名空间。
  • 6. 为什么使用模块更确切的说,从抽象的视角来看,模块至少有三个角色: 1、代码重用 模块可以在文件中永久保存代码,可以按照需要任意次重新载入和重新运行模块。除此之外,模块还是定义变量名的空间,被认作是模块的属性,可以被多个外部客户端引用 2、系统命名空间的划分 模块在Python中是最高级别的程序组织单元,从根本上讲,他们不过是变量名的软件包。模块将变量名封装进自包含的软件包,这样就可以避免变量名的冲突。如果不精确导入文件的话,我们不可能看到另一个文件中的变量名。 事实上,所有的一切都“存在于”模块文件中,执行的代码以及创建的对象都毫无疑问的封装在模块之中。正是由于这一点,模块是组织系统组件的天然工具。
  • 7. 为什么使用模块实现共享服务和数据 从操作的角度看,模块可以方便的实现跨系统共享的组件,而且只需要一个拷贝即可。如,如果需要一个全局对象,这个对象会被一个以上的函数或文件使用,可以将它编写在一个模块中以便能够被多个客户端导入
  • 8. Python程序架构实际上,真正的系统通常不仅仅涉及到一个文件,除了简单的脚本之外,程序都会采用多文件系统的形式。即使是编写的单个脚本,也会用到其他人已经写好的外部文件。
  • 9. 如何组织一个程序一般来讲,一个Python程序包括了多个模块文件。程序是作为一个主体的、顶层的文件来构造,配合有多个支持的文件。 在Python中,顶层文件包含了程序的主要控制流程,是启动应用的文件。模块文件就是工具的库,这些工具用来收集顶层文件使用的组件。顶层文件使用了模块文件中定义的工具,而模块又使用了其他模块所定义的工具。 模块文件通常在运行时不需直接做任何事情,然后,他们定义的工具会在其他文件中使用。在Python中,一个文件通过导入一个模块来获得这个模块定义的工具的访问权,这些工具被认作是模块的属性。
  • 10. Python程序架构 一个程序是一个模块的系统,它有一个顶层脚本文件a.py(启动后可运行的程序)以及多个模块文件b.py、c.py(用来导入工具库)。顶层脚本和模块都包含了自己编写的Python语句。Python标准库提供了一系列的预先编写好的模块
  • 11. 创建模块任何一个py文件都是一个模块,因此,我们只要在py文件中定义变量、函数、类即可 一个模块既可以作为主模块被Python运行(启动模块),也可以被其他模块导入。运行此模块和导入模块都是执行模块内的语句,没有任何差别。
  • 12. 创建模块建立m1.py如下: 运行m1.py,查看结果 导入m1.py,查看结果(在m2.py中)name = 'python' def hello(): print "hello\n" if __name__ == "__main__": print "runned" hello() else: print "imported"
  • 13. 使用现有的模块首先,利用import语句导入datetime模块,这句语句告诉Python,我们想要使用这个模块。datetime模块包含了与和时间日期处理相关的类和函数。 当Python执行import datetime语句的时候,它在sys.path变量所列目录中寻找datetime.py模块。如果找到了这个文件,就在内存中生成一个模块对象,并执行模块文件中的语句来填充模块对象的属性;然后在当前模块的名字空间中用datetime名字绑定此对象,我们就可以使用datetime所指向的模块对象的各种工具了。import datetime print datetime.date.today() print datetime.MAXYEAR2010-09-25 9999>>> import sys >>> sys.path ['', 'C:\\WINDOWS\\system32\\python26.zip', 'D:\\Python26\\Lib', 'D:\\Python26\\DLLs', 'D:\\Python26\\Lib\\lib-tk', 'C:\\Documents and Settings\\Administrator', 'D:\\Python26', 'D:\\Python26\\lib\\site-packages', 'D:\\Python26\\lib\\site-packages\\win32', 'D:\\Python26\\lib\\site-packages\\win32\\lib', 'D:\\Python26\\lib\\site-packages\\Pythonwin']
  • 14. 模块导入import x as y 将模块x导入,并另起个名字叫y from x import a,b,c 从x模块中导入其中的某些属性a,b,c到本模块的名字空间(即本模块的属性) 查看m3.py
  • 15. 模块导入import m1 import m1 as hellom from m1 import name print m1.name print name name = 'cc' m1.name= 'bb' hellom.name = 'hello name' hellom.hello()
  • 16. 模块导入模块导入只发生一次 模块会在第一次import或from时载入并运行,并且只在第一次时如此。这是故意安排的,因为导入模块的操作开销较大,在默认情况下,Python只保留一个模块文件的一个模块对象在内存中,之后的导入操作都只是将此模块对象绑定到正在执行的模块名字空间中 系统已经导入的全部模块对象放在sys模块的sys.modules属性中,它是一个字典对象
  • 17. 命名空间Python是面向对象的语言,其中一切事物都是对象,包括整数、浮点数、字符串、模块、类、类实体对象甚至函数等;对象的属性或方法又是另外的对象,依次嵌套构成。 每个对象如果要被当前代码使用必须要有唯一的名字,Python使用命名空间来跟踪记录各种对象,命名空间实际上可以看作是一个字典,键是对象的名称,值是对象本身,换句话说:命名空间是从命名到对象的映射字典。 在Python中每个对象都有自己的命名空间,比如类的实体对象,它所有的属性和方法构成的字典其实就是它的命名空间,当访问一个对象的属性或方法时,实际上就是在对象的命名空间查找名称对应的对象。
  • 18. 命名空间程序运行过程中如果要使用对象,首先在当前代码可见的命名空间查找对象,然后再在对象的名字空间查找对象的属性或方法。 在Python程序的任何执行点上,都有几个可见的命名空间,即当前代码可以使用这几个命名空间中的任何对象而不用加任何前缀引用。 一般来说有三个名字空间:local名字空间、global名字空间、built-in名字空间。这三个名字空间会随着代码运行动态的生成、更新、切换,一般一个栈帧(Frame)拥有独立的三个名字空间。栈帧可以认为是能够运行的一段段代码的运行环境,保存代码运行的各种信息,三个名字空间就保存在栈帧中。类似于C语言的运行时栈,函数调用时保存当前的栈帧A(入栈),生成一个新的栈帧B,填充函数执行所需要的各种信息(传递的参数等),运行函数代码,运行完成后销毁B,将栈帧A出栈,继续执行调用前的代码。
  • 19. 命名空间可见,栈帧是动态生成的,模块被首次导入或函数调用时都会生成新的栈帧,并设置每个栈帧的三个名字空间。栈帧的三个名字空间按下面的规则设置: 1、所有栈帧的built-in名字空间其实是同一个空间,里面存放着各种内置的函数和异常类定义,对应着__builtin__模块,在Python运行环境初始化时加载进内存。 2、模块导入生成的栈帧的local名字空间和global名字空间是同一个名字空间,而且这两个名字空间也就是模块本身的名字空间(存放在模块的__dict__属性中),里面存放模块所定义的函数、类、变量。两个命名空间在执行模块语句前创建,并在模块代码执行中填充。 3、函数调用生成的栈帧的global名字空间是函数所在模块的global名字空间,注意的是,不是调用模块的global名字空间。而local名字空间是函数自有的,当被调用的时候动态生成,里面包括函数传进来的参数变量和函数内部定义的临时变量。每次发生函数调用时,在执行函数代码之前,生成新的local名字空间,而global空间直接从函数对象的func_globals拷贝而来,而func_globals是在函数定义时设置的,设置的值就是定义时的global空间,因此函数调用时的global空间就是函数定义所在模块的global空间。
  • 20. 命名空间当代码访问一个对象x时,Python将在当前代码(当前栈帧)的三个名字空间查找x对象,然后在x对象自己的名字空间查找其属性或方法。 查找的顺序服从LGB规则,即依次是:local名字空间、global名字空间、built-in名字空间,如果在靠前的名字空间中找到了名字为x的对象,则停止搜索;否则直到搜索完built-in空间。如果在三个名字空间中都没有名字为x的对象,Python则引发一个“NameError”的异常,消息是“There is no variable named 'x'”,说明在当前代码中不能使用x对象。 Python的一个特别之处在于其赋值操作总是在最里层的作用域。赋值不会复制数据――只是将命名绑定到对象。删除也是如此:‘del x’ 只是从局部作用域的命名空间中删除命名x。事实上,所有引入新命名的操作都作用于局部作用域。
  • 21. 模块的命名空间模块本身也是对象,因此,也有自己的命名空间,而存在于模块之内的变量名、类、函数就是模块对象的属性,存在于模块的命名空间 模块语句会在首次导入时执行 模块在第一次导入时,无论在什么地方,Python都会建立空的模块对象,并逐一执行该模块文件内的语句,依照文件从头到尾的顺序。
  • 22. 模块的命名空间顶层的赋值语句会创建模块属性 在导入时,文件顶层(不在def或class之内)赋值变量的语句(如=、def、import等),会建立模块对象的属性;赋值的变量名会存储在模块的命名空间内。 模块的命名空间能够通过属性__dict__或dir(m)获取 由导入而建立的模块命名空间也是字典,可以通过模块对象内置的__dict__属性来读取,而且能通过函数dir来查看。
  • 23. 模块的命名空间模块是一个独立的作用域 在模块中,本地变量就是全局变量,和函数不同,函数调用结束后本地变量就不在保存,而模块在导入后,本地变量会变成模块对象的属性,保存在模块对象的命名空间。 模块函数中如果使用了global关键字,则会在在模块顶层变量中查找
  • 24. 作用域如第一个模块moda.py,函数f中使用了全局X 模块modb.py,定义自己的全局变量X,并调用moda的函数 执行时,moda.f修改moda中的X,而不是modb中的x,moda.f的全局作用域一定是在其所在的文件,无论这个函数是由哪个文件调用。X = 88 def f(): global X X = 99X = 11 import moda moda.f() print X, moda.X
  • 25. 作用域换句话说,导入操作不会赋予被导入文件中的代码对上层代码的可见度:被导入文件无法看到进行导入文件内的变量名 函数绝对无法看到其他函数内的变量名 模块程序代码绝对无法看到其他模块内的变量名,除非进行了明确的导入 在Python中,一段程序的作用域完全由程序所处的文件中实际位置决定,作用域绝不会被函数调用或模块导入影响
  • 26. 重载模块由于模块只导入一次,如果修改了模块文件代码想重新导入模块,则可以使用reload函数 reload(modulename) 相当于 del sys.modules['modulename'] import modulename 演示reload rem.py
  • 27. 包(package)package包是一组module的集合,一个文件夹下面只要有个__init__.py 文件,这个文件夹就可以看作是一个包,用以下方法创建一个包 先在当前目录创建一个目录testpackage 在testpackage下创建一个空文件__init__.py 在testpackage中创建一个testmodule.py,里面编写任意代码。 启动Python,运行: >>> import testpackage.testmodule >>> testpackage.testmodule.sayHello() hello
  • 28. 包(package)包是一种组织模块的方法,提供了一个命名空间,防止发生名字冲突 包中还可以有包,所以这种方式可以很好的组织一个树状结构,用来管理多个模块
  • 29. 本章结束,谢谢!