Python 基础
Python 基础
单行注释:#
多行注释:用多个 # 号,还有 ''' 和 """
# 第一个注释
# 第二个注释
'''
第三注释
第四注释
'''
"""
第五注释
第六注释
"""
类型
数字
字符串
列表 == 数组
元组 == 不可变数组,并用()
字典 == map集合,key-value:键必须是唯一的,但值则不必
集合 == set集合,集合(set)是一个无序的不重复元素序列
字符串(String)
- python中单引号和双引号使用完全相同。
- 使用三引号('''或""")可以指定一个多行字符串。
- 转义符 ''
- 反斜杠可以用来转义,使用r可以让反斜杠不发生转义。。 如 r"this is a line with \n" 则\n会显示,并不是换行。
- 按字面意义级联字符串,如"this " "is " "string"会被自动转换为this is string。
- 字符串可以用 + 运算符连接在一起,用 * 运算符重复。
- Python 中的字符串有两种索引方式,从左往右以 0 开始,从右往左以 -1 开始。
- Python中的字符串不能改变。
- Python 没有单独的字符类型,一个字符就是长度为 1 的字符串。
- 字符串的截取的语法格式如下:变量[头下标:尾下标:步长]
条件控制:if 语句
语法格式如下:
if condition_1:
statement_block_1
elif condition_2:
statement_block_2
else:
statement_block_3
例子:
var1 = 2
if var1 == 2:
print ("if 表达式条件为 true")
# 结果:
# if 表达式条件为 true
循环控制
while 循环
语法格式如下:
while 判断条件(condition):
执行语句(statements)……
例子:
count = 0
while count < 2:
count += 1
print('count:',count)
# 结果
# count: 1
# count: 2
while 循环使用 else 语句
如果 while 后面的条件语句为 false 时,则执行 else 的语句块。
语法格式如下:
while <expr>:
<statement(s)>
else:
<additional_statement(s)>
for 语句
语法格式如下:
for <variable> in <sequence>:
<statements>
else:
<statements>
例子:
for i in range(2):
print('value:',i)
# 结果:
# value: 0
# value: 1
跳出循环
break 语句:可以跳出 for 和 while 的循环体。如果你从 for 或 while 循环中终止,任何对应的循环 else 块将不执行。
continue 语句:被用来告诉 Python 跳过当前循环块中的剩余语句,然后继续进行下一轮循环。
迭代器与生成器
迭代器
- 迭代是Python最强大的功能之一,是访问集合元素的一种方式。
- 迭代器是一个可以记住遍历的位置的对象。
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
- 迭代器有两个基本的方法:iter():创建迭代器对象 和 next():输出迭代器的下一个元素。
- 字符串,列表或元组对象都可用于创建迭代器:
例子:
list=[1,2]
it = iter(list) # 创建迭代器对象
for x in it:
print (x)
# 结果:
# 1
# 2
例子:使用 next()
list=[1,2]
it = iter(list) # 创建迭代器对象
print(next(it))
print(next(it))
# 结果:
# 1
# 2
生成器
- 在 Python 中,使用了 yield 的函数被称为生成器(generator)。
- 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
- 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
- 调用一个生成器函数,返回的是一个迭代器对象。
例子:
def intNum():
print("开始执行")
for i in range(3):
yield i
print("继续执行")
num = intNum() # 创建有 num 的生成器
# 调用 next() 内置函数:执行到yield
print(next(num))
# 调用 __next__() 方法,接着上次位置执行:执行到yield
print(num.__next__())
# 通过for循环遍历生成器:不断调用 next() 函数
for i in num:
print(i)
#结果:
# 开始执行
# 0
# 继续执行
# 1
# 继续执行
# 2
# 继续执行
例子执行流程:
-
首先,在创建有 num 生成器的前提下,通过其调用 next() 内置函数,会使 Python 解释器开始执行 intNum() 生成器函数中的代码,因此会输出“开始执行”,程序会一直执行到
yield i
,而此时的 i==0,因此 Python 解释器输出“0”。由于受到 yield 的影响,程序会在此处暂停。 -
然 后,我们使用 num 生成器调用 next() 方法,该方法的作用和 next() 函数完全相同(事实上,next() 函数的底层执行的也是 next() 方法),它会是程序继续执行,即输出“继续执行”,程序又会执行到
yield i
,此时 i==1,因此输出“1”,然后程序暂停。 -
最后,我们使用 for 循环遍历 num 生成器,之所以能这么做,是因为 for 循环底层会不断地调用 next() 函数,使暂停的程序继续执行,因此会输出后续的结果。
函数
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号 : 起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。
例子:
# 可写函数说明
def sum(arg1, arg2):
# 返回2个参数的和."
total = arg1 + arg2
print("函数内 : ", total)
return total
# 调用sum函数
total = sum(10, 20)
print("函数外 : ", total)
# 结束:
# 函数内 : 30
# 函数外 : 30
数据结构
列表
Python中列表是可变的,这是它区别于字符串和元组的最重要的特点,一句话概括即:列表可以修改,而字符串和元组不能。
list.append(x) | 把一个元素添加到列表的结尾,相当于 a[len(a):] = [x]。 |
---|---|
list.extend(L) | 通过添加指定列表的所有元素来扩充列表,相当于 a[len(a):] = L。 |
list.insert(i, x) | 在指定位置插入一个元素。第一个参数是准备插入到其前面的那个元素的索引,例如 a.insert(0, x) 会插入到整个列表之前,而 a.insert(len(a), x) 相当于 a.append(x) 。 |
list.remove(x) | 删除列表中值为 x 的第一个元素。如果没有这样的元素,就会返回一个错误。 |
list.pop([i]) | 从列表的指定位置移除元素,并将其返回。如果没有指定索引,a.pop()返回最后一个元素。元素随即从列表中被移除。(方法中 i 两边的方括号表示这个参数是可选的,而不是要求你输入一对方括号,你会经常在 Python 库参考手册中遇到这样的标记。) |
list.clear() | 移除列表中的所有项,等于del a[:]。 |
list.index(x) | 返回列表中第一个值为 x 的元素的索引。如果没有匹配的元素就会返回一个错误。 |
list.count(x) | 返回 x 在列表中出现的次数。 |
list.sort() | 对列表中的元素进行排序。 |
list.reverse() | 倒排列表中的元素。 |
list.copy() | 返回列表的浅复制,等于a[:]。 |
集合
集合是一个无序不重复元素的集。基本功能包括关系测试和消除重复元素。
嵌套列表解析
列表推导式提供了从序列创建列表的简单途径。通常应用程序将一些操作应用于某个序列的每个元素,用其获得的结果作为生成新列表的元素,或者根据确定的判定条件创建子序列。
每个列表推导式都在 for 之后跟一个表达式,然后有零到多个 for 或 if 子句。返回结果是一个根据表达从其后的 for 和 if 上下文环境中生成出来的列表。如果希望表达式推导出一个元组,就必须使用括号。
说明:
[x*y for x in vec1 for y in vec2]
的执行顺序:
for x in vec1:
for y in vec2:
x*y
例子:
vec1 = [2, 4, 6]
vec2 = [4, 3, -9]
value1 = [x * y for x in vec1 for y in vec2]
print("value1:", value1)
value2 = []
for x in vec1:
for y in vec2:
value2.append(x * y)
print("value2:", value2)
# 结果:
# value1: [8, 6, -18, 16, 12, -36, 24, 18, -54]
# value2: [8, 6, -18, 16, 12, -36, 24, 18, -54]
遍历字典
在字典中遍历时,关键字和对应的值可以使用 items() 方法同时解读出来
例子:
knights = {'one': 'The One', 'two': 'The Two'}
for k, v in knights.items():
print(k, v)
# 结果:
# one The One
# two The Two
例子:使用 enumerate() 函数:
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
knights = {'one': 'The One', 'two': 'The Two'}
for i, v in enumerate(knights):
print(i, v)
# 结果:
# 0 one
# 1 two
模块
import 语句
想使用 Python 源文件,只需在另一个源文件里执行 import 语句。一个模块只会被导入一次,不管你执行了多少次import。语法如下:
import module1[, module2[,... moduleN]
例子:
# 导入模块
import support
# 现在可以调用模块里包含的函数了
support.print_func("Runoob")
from … import 语句
Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中,语法如下:
from modname import name1[, name2[, ... nameN]]
例子:
from fibo import fib, fib2
输入和输出
%格式化操作符
% 操作符也可以实现字符串格式化。 它将左边的参数作为类似 sprintf() 式的格式化字符串, 而将右边的代入, 然后返回格式化后的字符串.
例子:
value3 = 9
print('value3的值为:%i' % value3)
# 结果:
# value3的值为:9
读取键盘输入
Python 提供了 input() 内置函数从标准输入读入一行文本,input() 默认输入的为 str 格式,默认的标准输入是键盘。
str1 = input("请输入:")
print("你输入的内容是: ", str1)
# 结果:
# 请输入:憨憨
# 你输入的内容是: 憨憨
读和写文件
open() 将会返回一个 file 对象,基本语法格式如下:
open(filename, mode)
- filename:包含了你要访问的文件名称的字符串值。
- mode:决定了打开文件的模式:只读,写入,追加等。所有可取值见如下的完全列表。这个参数是非强制的,
默认文件访问模式为只读(r)
。
模式 | 描述 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
例子:
# 打开一个文件
f = open("./foo.txt", "w")
# 向里面写入内容
num = f.write("Python 是一个非常好的语言。\n是的,的确非常好!!\n")
print(num)
# 关闭打开的文件
f.close()
# 结果:
# 29
文件对象的方法
剩下的例子假设已经创建了一个称为 f 的文件对象。
f.read()
-
为了读取一个文件的内容,调用 f.read(size), 这将读取一定数目的数据, 然后作为字符串或字节对象返回。
-
size 是一个可选的数字类型的参数。 当 size 被忽略了或者为负, 那么该文件的所有内容都将被读取并且返回。
例子:
# 打开一个文件
f = open("./foo.txt", "r")
str1 = f.read()
print(str1)
# 关闭打开的文件
f.close()
# 结果:
# Python 是一个非常好的语言。
# 是的,的确非常好!!
f.readline()
- f.readline() 会从文件中读取单独的一行。换行符为 '\n'。f.readline() 如果返回一个空字符串, 说明已经已经读取到最后一行。
例子:
# 打开一个文件
f = open("./foo.txt", "r")
str1 = f.readline()
print(str1)
# 关闭打开的文件
f.close()
# 结果:
# Python 是一个非常好的语言。
f.readlines()
-
f.readlines() 将返回该文件中包含的所有行。
-
如果设置可选参数 sizehint, 则读取指定长度的字节, 并且将这些字节按行分割。
例子:
# 打开一个文件
f = open("./foo.txt", "r")
str1 = f.readlines()
print(str1)
# 关闭打开的文件
f.close()
# 结果:
f.write()
- f.write(string) 将 string 写入到文件中, 然后返回写入的字符数。
f.tell()
- f.tell() 返回文件对象当前所处的位置, 它是从文件开头开始算起的字节数。
f.close()
-
在文本文件中 (那些打开文件的模式下没有 b 的), 只会相对于文件起始位置进行定位。
-
当你处理完一个文件后, 调用 f.close() 来关闭文件并释放系统的资源,如果尝试再调用该文件,则会抛出异常。
pickle 模块
- python的pickle模块实现了基本的数据序列和反序列化。
- 通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储。
- 通过pickle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象。
4个函数:
- dumps():将 Python 中的对象序列化成二进制对象,并返回;
- loads():读取给定的二进制对象数据,并将其转换为 Python 对象;
- dump():将 Python 中的对象序列化成二进制对象,并写入文件;
- load():读取指定的序列化数据文件,并返回对象。
File(文件) 方法
open() 方法
Python open() 方法用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError。
注意:使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法。
完整的语法格式为:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
参数说明:
- file: 必需,文件路径(相对或者绝对路径)。
- mode: 可选,文件打开模式
- buffering: 设置缓冲
- encoding: 一般使用utf8
- errors: 报错级别
- newline: 区分换行符
- closefd: 传入的file参数类型
- opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。
file 对象
file 对象使用 open 函数来创建,下表列出了 file 对象常用的函数:
序号 | 方法及描述 |
---|---|
1 | file.close()关闭文件。关闭后文件不能再进行读写操作。 |
2 | file.flush()刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。 |
3 | file.fileno()返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。 |
4 | file.isatty()如果文件连接到一个终端设备返回 True,否则返回 False。 |
5 | file.next()Python 3 中的 File 对象不支持 next() 方法。返回文件下一行。 |
6 | [file.read(size])从文件读取指定的字节数,如果未给定或为负则读取所有。 |
7 | [file.readline(size])读取整行,包括 "\n" 字符。 |
8 | [file.readlines(sizeint])读取所有行并返回列表,若给定sizeint>0,返回总和大约为sizeint字节的行, 实际读取值可能比 sizeint 较大, 因为需要填充缓冲区。 |
9 | [file.seek(offset, whence])移动文件读取指针到指定位置 |
10 | file.tell()返回文件当前位置。 |
11 | [file.truncate(size])从文件的首行首字符开始截断,截断文件为 size 个字符,无 size 表示从当前位置截断;截断之后后面的所有字符被删除,其中 windows 系统下的换行代表2个字符大小。 |
12 | file.write(str)将字符串写入文件,返回的是写入的字符长度。 |
13 | file.writelines(sequence)向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。 |
OS 文件/目录方法
os
就是“operating system”的缩写,顾名思义,os
模块提供的就是各种 Python 程序与操作系统进行交互的接口。通过使用os
模块,一方面可以方便地与操作系统进行交互,另一方面页可以极大增强代码的可移植性。如果该模块中相关功能出错,会抛出OSError
异常或其子类异常。
os模块的常用功能:
-
os.name #显示当前使用的平台
-
os.getcwd() #显示当前python脚本工作路径
-
os.listdir('dirname') #返回指定目录下的所有文件和目录名
-
os.remove('filename') #删除一个文件
-
os.makedirs('dirname/dirname') #可生成多层递规目录
-
os.rmdir('dirname') #删除单级目录
-
os.rename("oldname","newname") #重命名文件
-
os.system() #运行shell命令,注意:这里是打开一个新的shell,运行命令,当命令结束后,关闭shell
-
os.sep #显示当前平台下路径分隔符
-
os.linesep #给出当前平台使用的行终止符
-
os.environ #获取系统环境变量
-
os.path.abspath(path) #显示当前绝对路径
-
os.path.dirname(path) #返回该路径的父目录
-
os.path.basename(path) #返回该路径的最后一个目录或者文件,如果path以/或\结尾,那么就会返回空值。
-
os.path.isfile(path) #如果path是一个文件,则返回True
-
os.path.isdir(path) #如果path是一个目录,则返回True
-
os.stat() #获取文件或者目录信息
-
os.path.split(path) #将path分割成路径名和文件名。(事实上,如果你完全使用目录,它也会将最后一个目录作为文件名而分离,同时它不会判断文件或目录是否存在)
-
os.path.join(path,name) #连接目录与文件名或目录 结果为path/name
错误和异常
错误
Python 的语法错误或者称之为解析错
异常
即便 Python 程序的语法是正确的,在运行它的时候,也有可能发生错误。运行期检测到的错误被称为异常。
异常处理:try/except
异常捕捉可以使用 try/except 语句。
例子:
try:
print("尝试执行 try 中的代码")
except ValueError:
print("如果发生错误,会执行这里的代码")
异常处理:try/except...else
try/except 语句还有一个可选的 else 子句,如果使用这个子句,那么必须放在所有的 except 子句之后。else 子句将在 try 子句没有发生任何异常的时候执行。
异常处理:try-finally 语句
try-finally 语句无论是否发生异常都将执行最后的代码。
抛出异常
Python 使用 raise 语句抛出一个指定的异常。raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类)。
raise语法格式如下:
raise [Exception [, args [, traceback]]]
例子:
x = 10
if x > 5:
raise Exception('x 不能大于 5。x 的值为: {}'.format(x))
# 结果:
# Exception: x 不能大于 5。x 的值为: 10
面向对象
面向对象技术简介
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 方法:类中定义的函数。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
类定义
类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。
语法格式如下:
class ClassName:
<statement-1>
.
.
.
<statement-N>
self代表类的实例,而非类
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。
类对象
类对象支持两种操作:属性引用和实例化。
类的方法
在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例。
# 一个简单的类实例class MyClass: # 类的属性 i = 12345 j = 0 # 定义私有属性,私有属性在类外部无法直接进行访问 __weight = 0 # 类的构造方法,该方法在类实例化时会自动调用 def __init__(self): self.j = 2 # 类的方法 def show(self): return 'hello world'# 实例化类x = MyClass()# 访问类的属性和方法print("MyClass 类的属性 i 为:", x.i)print("MyClass 类的方法 show 输出为:", x.show())# 结果:# MyClass 类的属性 i 为: 12345# MyClass 类的方法 show 输出为: hello world
继承
Python 同样支持类的继承,如果一种语言不支持继承,类就没有什么意义。派生类的定义如下所示:
class DerivedClassName(BaseClassName): <statement-1> . . . <statement-N>
子类(派生类 DerivedClassName)会继承父类(基类 BaseClassName)的属性和方法。BaseClassName(实例中的基类名)必须与派生类定义在一个作用域内。
class DerivedClassName(modname.BaseClassName):
多继承
Python同样有限的支持多继承形式。多继承的类定义形如下例:
class DerivedClassName(Base1, Base2, Base3): <statement-1> . . . <statement-N>
需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。
方法重写
- 如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法。
- 用子类对象调用已被覆盖的方法,会执行子类的方法
- 用父类对象调用父类的方法,执行的是父类的方法
基础重载方法
下表列出了一些通用的功能,你可以在自己的类重写:
序号 | 方法, 描述 & 简单的调用 |
---|---|
1 | init ( self [,args...] ) 构造函数 简单的调用方法: obj = className(args) |
2 | del( self ) 析构方法, 删除一个对象 简单的调用方法 : dell obj |
3 | repr( self ) 转化为供解释器读取的形式 简单的调用方法 : repr(obj) |
4 | str( self ) 用于将值转化为适于人阅读的形式 简单的调用方法 : str(obj) |
5 | cmp ( self, x ) 对象比较 简单的调用方法 : cmp(obj, x) |
类属性与方法
类的私有属性
__private_attrs:两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。
类的方法
在类地内部,使用 def 关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数。
类的私有方法
__private_method:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用 self.__private_methods。
命名空间和作用域
命名空间和作用域(和变量的作用域差不多)
命名空间
- 命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。
- 命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。
一般有三种命名空间:
- 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
- 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
- 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
命名空间查找顺序:
- 局部的命名空间 -> 全局命名空间 -> 内置命名空间。
命名空间的生命周期:
- 命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。
作用域
作用域就是一个 Python 程序可以直接访问命名空间的正文区域。
- L(Local):最内层,包含局部变量,比如一个函数/方法内部。
- E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
- G(Global):当前脚本的最外层,比如当前模块的全局变量。
- B(Built-in): 包含了内建的变量/关键字等,最后被搜索。
规则顺序: L –> E –> G –> gt –> B。
在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。
global 和 nonlocal关键字
global :将变量变为全局变量
nonlocal : 修改嵌套作用域(enclosing 作用域,外层非全局作用域)
当内部作用域想修改外部作用域的变量时,就要用到 global 和 nonlocal 关键字了。
例子:global
num = 10def inner(): global num # global 关键字声明 num = 100 print(num)inner()print(num)# 结果:# 100# 100
例子:nonlocal :将嵌套的内层的作用域修改到嵌套的外层
def outer(): num = 100 def inner(): nonlocal num # nonlocal关键字声明 num = 10 print(num) inner() print(num)outer()# 结果:# 10# 10
标准库概览
操作系统接口
os模块提供了不少与操作系统相关联的函数。
文件通配符
glob模块提供了一个函数用于从目录通配符搜索中生成文件列表:
命令行参数
通用工具脚本经常调用命令行参数。这些命令行参数以链表形式存储于 sys 模块的 argv 变量。
错误输出重定向和程序终止
sys 还有 stdin,stdout 和 stderr 属性,即使在 stdout 被重定向时,后者也可以用于显示警告和错误信息。
字符串正则匹配
re模块为高级字符串处理提供了正则表达式工具。对于复杂的匹配和处理,正则表达式提供了简洁、优化的解决方案:
数学
math模块为浮点运算提供了对底层C函数库的访问:
访问 互联网
有几个模块用于访问互联网以及处理网络通信协议。其中最简单的两个是用于处理从 urls 接收的数据的 urllib.request 以及用于发送电子邮件的 smtplib:
日期和时间
datetime模块为日期和时间处理同时提供了简单和复杂的方法。
支持日期和时间算法的同时,实现的重点放在更有效的处理和格式化输出。
- 今天
today = datetime.date.today()
- 昨天
yesterday = today - datetime.timedelta(days=1)
- 上个月
last_month = today.month - 1 if today.month - 1 else 12
- 当前时间戳
time_stamp = time.time()
- 时间戳转datetime
datetime.datetime.fromtimestamp(time_stamp)
- datetime转时间戳
int(time.mktime(today.timetuple()))
- datetime转字符串
today_str = today.strftime("%Y-%m-%d")
- 字符串转datetime
today = datetime.datetime.strptime(today_str, "%Y-%m-%d")
- 补时差
today + datetime.timedelta(hours=8)
数据压缩
以下模块直接支持通用的数据打包和压缩格式:zlib,gzip,bz2,zipfile,以及 tarfile。
性能度量
有些用户对了解解决同一问题的不同方法之间的性能差异很感兴趣。
测试模块
开发高质量软件的方法之一是为每一个函数开发测试代码,并且在开发过程中经常进行测试
doctest模块提供了一个工具,扫描模块并根据程序中内嵌的文档字符串执行测试。
测试构造如同简单的将它的输出结果剪切并粘贴到文档字符串中。