目录
模块:用来组织代码
-
概念/目的:为了避免再次进入python解释器时重新定义(函数和变量),并将过长的程序进行拆分管理,或者便于在不同的程序中使用同一个便捷的函数,因此把定义放在一个文件里,并在脚本或解释器的交互式实例中使用它们(模块)。
-
本质:模块是一个包含Python定义和语句的文件。文件名就是模块名后跟文件后缀 .py 。
探索模块
模块的结构布局
包:用来组织模块
类:用来组合数据和功能
类(Class)和实例(Instance)是面向对象最重要的两个概念。
类是抽象的模板,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
类的概念
类提供了一种组合数据和功能的方法。 创建一个新类意味着创建一个新的对象 类型,从而允许创建一个该类型的新 实例 。 每个类的实例可以拥有保存自己状态的属性。 一个类的实例也可以有改变自己状态的(定义在类中的)方法。
创建类和实例
类的操作
类对象支持两种操作:属性引用和实例化。
- 属性引用 使用 Python 中所有属性引用所使用的标准语法: obj.name。
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
MyClass.i 和 MyClass.f 就是有效的属性引用,将分别返回一个整数和一个函数对象。
doc 也是一个有效的属性,将返回所属类的文档字符串: “A simple example class”。
- 类的实例化 使用函数表示法。 可以把类对象视为是返回该类的一个新实例的不带参数的函数。举例来说(假设使用上述的类):
x = MyClass()
创建类的新 实例 并将此对象分配给局部变量 x。
-
实例对象
实例对象理解的唯一操作是属性引用。有两种有效的属性名称,数据属性和方法。
补充
作用域、命名空间和 LEGB 原则
作用域 = 命名空间
在一个模块中,我们可能会定义很多函数和变量,但有的函数和变量我们希望给别人使用,有的函数和变量我们希望仅仅在模块内部使用。在Python中,是通过_前缀来实现的。
- 正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,x123,
- 类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途 -> 用于类和子类
- 类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用 -> 仅仅用于类自己(子类也不能引用)
具体地说,在代码中变量名被赋值(Python 中变量声明即赋值,global 声明的只是变量的使用域)的位置决定了该变量能被访问的范围。函数定义了本地作用域,而模块定义的是全局作用域。这两个作用域之前有如下关系:
-
每一个模块都是全局作用域。也就是说,创建于模块文件顶层的变量具有全局作用域,对于外部访问就成了一个模块对象的属性。
-
全局作用域的作用范围仅限于单个文件。“全局”指的是在一个文件的顶层变量名对于这个文件而言是全局的。
-
每次对函数的调用都创建了一个新的本地作用域。Python 中也有递归,即可以调用自身,每次调用都会创建五个新的本地命名空间。
-
赋值的变量名除非声明为全局变量,否则均为本地变量。如果需要在函数内部对模块文件顶层的变量名赋值,需要在函数内部通过 global 语句声明该变量。
-
所有的变量可归纳为本地、全局或者内置三种。范围分别为 def 内部,在一个模块的命名空间内部和预定义的 builtin 模块提供的变量。
命名空间 = 作用域
在 Python 程序中创建、改变或查找变量名时,都是在一个保存变量名的地方进行中,那个地方我们称之为命名空间。作用域这个术语也称之为命名空间。
白话一点讲:命名空间是对变量名的分组划分。 不同组的相同名称的变量视为两个独立的变量,因此隶属于不同分组(即命名空间)的变量名可以重复。
命名空间可以存在多个,使用命名空间,表示在该命名空间中查找当前名称。
LEGB 原则
LEGB含义解释:
L-Local(function);函数内的名字空间
E-Enclosing function locals;外部嵌套函数的名字空间(例如closure)
G-Global(module);函数定义所在模块(文件)的名字空间
B-Builtin(Python);Python内置模块的名字空间
前面讲到,Python的命名空间是一个字典,字典内保存了变量名称与对象之间的映射关系,因此,查找变量名就是在命名空间字典中查找键-值对。
Python有多个命名空间,因此,需要有规则来规定,按照怎样的顺序来查找命名空间,LEGB就是用来规定命名空间查找顺序的规则。
LEGB规定了查找一个名称的顺序为:local–>enclosing function locals–>global–>builtin
另解:
在函数命名空间中:
- 变量名引用分为三个作用域进行查找:首先是本地,然后是函数内(如果有的话),之后是全局,最后是内置。
- 在默认情况下,变量名赋值会创建或者改变本地变量。
- 全局声明将会给映射到模块文件内部的作用域的变量名赋值。
Python 的变量名解析机制也称为 LEGB 法则,具体如下:
当在函数中使用未确定的变量名时,Python 搜索 4 个作用域:本地作用域(L),之后是上一层嵌套结构中 def 或 lambda 的本地作用域(E),之后是全局作用域(G),最后是内置作用域(B)。按这个查找原则,在第一处找到的地方停止。如果没有找到,Python 会报错的。
标准文件模板
运行测试
举例
Python本身就内置了很多非常有用的模块,只要安装完毕,这些模块就可以立刻使用。
我们以内建的sys模块为例,编写一个hello的模块:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
' a test module '
__author__ = 'Michael Liao'
import sys
def test():
args = sys.argv
if len(args)==1:
print('Hello, world!')
elif len(args)==2:
print('Hello, %s!' % args[1])
else:
print('Too many arguments!')
if __name__=='__main__':
test()
第1行和第2行是标准注释,第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行,第2行注释表示.py文件本身使用标准UTF-8编码;
第4行是一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释;
第6行使用__author__变量把作者写进去,这样当你公开源代码后别人就可以瞻仰你的大名;
以上就是Python模块的标准文件模板,当然也可以全部删掉不写,但是,按标准办事肯定没错。
后面开始就是真正的代码部分。
注意到这两行代码:
if __name__=='__main__':
test()
当我们在命令行运行hello模块文件时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该hello模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。
更多细节可以参考 廖雪峰-使用模块
参考: