python基本语法(二)
条件控制语句:if – elif – else
在Python中没有switch – case语句
在嵌套 if 语句中,可以把 if...elif...else 结构放在另外一个 if...elif...else 结构中
循环语句:
while 循环: while 判断条件(condition): 执行语句(statements)……
在 Python 中没有 do..while 循环
无限循环:设置条件表达式永远不为 false 来实现无限循环, CTRL+C 来退出当前的无限循环
while 循环使用 else 语句: 在 while … else 在条件语句为 false 时执行 else 的语句块
for 语句: for循环可以遍历任何序列的项目,如一个列表或者一个字符串
格式如下: 可以不要else
for <variable> in <sequence>:
<statements>
else:
<statements>
break: 跳出当前循环体, 执行下一条语句块
continue: 跳过当前循环块中的剩余语句,然后继续进行下一轮循环
pass是空语句,是为了保持程序结构的完整性, 一般用做占位语句
函数:
range()函数:
生成数列: range(5): 生成0 - 4的数字
指定区间的值: range(5,9): 生成5 - 8的数字
指定数字开始并指定不同的增量(甚至可以是负数,有时这也叫做'步长'):
range(0, 10, 3): 生成0, 3, 6, 9的数字
range(-10, -100, -30): 生成 -10, -40, -70的负数
range()函数来创建一个列表: list(range(5)): 生成列表[0, 1, 2, 3, 4]
range()和len()函数结合使用: 遍历一个序列的索引, range(len(var))
eval():去掉参数最外侧引号并执行余下语句的函数,单引号、双引号、三引号
rjust(): 可以将字符串靠右, 并在左边填充空格, var.rjust(x): x为填充的空格数
zfill(): 在对象左边补足位数, 'qwer'.zfill(6) >>> 00qwer
ljust():
center():
迭代器: 访问集合元素的一种方式, 从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退
迭代器有两个基本的方法:
创建迭代器对象: iter() -> var = iter(list)
输出迭代器的下一个元素 : next() -> next(var), 每次只会输出一个元素, 可以循环输出
字符串,列表或元组对象都可用于创建迭代器
迭代器对象可以使用常规for语句进行遍历: for x in var
定义函数:
函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 (): def 函数名(参数列表): 函数体
默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的
return语句:
return [表达式]: 结束函数或退出函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None
参数:
必需参数: 必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样
关键字参数: 函数调用使用关键字参数来确定传入的参数值, 调用时允许参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值
函数: def printinfo( name, age ):
调用函数关键字入参:顺序不一致printinfo( age=50, name="runoob" )
默认参数: 没有传递参数,则会使用默认参数
函数: def printinfo( name, age = 35 ):
未传age参数:printinfo( name="runoob" )
不定长参数: 比函数声明时更多的参数。这些参数叫做不定长参数,声明时不会命名
函数: def functionname([formal_args,] *var_args_tuple ): 如def printinfo( arg1, *vartuple ): print (arg1, vartuple)
调用函数:printinfo( 70, 60, 50 ), 输出 70, (60, 50)
加了星号 * 的参数会以元组(tuple)的形式导入,加了两个星号 ** 的参数会以字典的形式导入, 存放所有未命名的变量参数
声明函数时,参数中星号 * 可以单独出现, 星号 * 后的参数必须用关键字传入: f(1,2,c=3), def f(a,b,*,c):
如果在函数调用时没有指定参数,它就是一个空元组。也可以不向函数传递未命名的变量
强制位置参数:Python3.8 新增了一个函数形参语法 / 用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式
def f(a, b, /, c, d, *, e, f):
形参 a 和 b 必须使用指定位置参数(相当必需参数入参),c 或 d 可以是位置形参或关键字形参,而 e 或 f 要求为关键字形参
f(10, b=20, c=30, d=40, e=50, f=60) # b 不能使用关键字参数的形式
f(10, 20, 30, 40, 50, f=60) # e 必须使用关键字参数的形式
匿名函数: 使用 lambda 来创建匿名函数, 即不再使用 def 语句这样标准的形式定义一个函数: lambda [arg1 [,arg2,.....argn]]:expression
lambda 只是一个表达式,而不是一个代码块, 函数体比 def 简单很多
lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数
lambda 函数的语法只包含一个语句: sum = lambda arg1, arg2: arg1 + arg2
数据结构:
列表:
将列表当做堆栈使用:
堆栈作为特定的数据结构,最先进入的元素最后一个被释放(后进先出)
用 append() 方法可以把一个元素添加到堆栈顶。用不指定索引的 pop() 方法可以把一个元素从堆栈顶释放出来
将列表当作队列使用:
在队列里第一加入的元素,第一个取出来;但是拿列表用作这样的目的效率不高
在列表的最后添加或者弹出元素速度快,然而在列表里插入或者从头部弹出速度却不快(因为所有其他的元素都得一个一个地移动)
列表推导式:
应用于某个序列的每个元素,用其获得的结果作为生成新列表的元素,或者根据确定的判定条件创建子序列
每个列表推导式都在 for 之后跟一个表达式,然后有零到多个 for 或 if 子句。返回结果是一个根据表达从其后的 for 和 if 上下文环境中生成出来的列表
如果希望表达式推导出一个元组,就必须使用括号
例子:
>>> vec = [2, 4, 6]
>>> [3*x for x in vec]
>>> [[x, x**2] for x in vec]
>>> [3*x for x in vec if x > 3]
>>> [x*y for x in vec1 for y in vec2]
>>> [vec1[i]*vec2[i] for i in range(len(vec1))]
>>> [str(round(355/113, i)) for i in range(1, 6)]
嵌套列表解析:
例子:
>>> matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
>>> [[row[i] for row in matrix] for i in range(4)]
输出4X3列表:[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
del 语句:
可以从一个列表中依索引而不是值来删除一个元素。这与使用 pop() 返回一个值不同
可以用 del 语句从列表中删除一个切割,或清空整个列表
也可以用 del 删除实体变量: del a
例子: del a[0], del a[2:4], del a[:]
集合:
集合推导式:a = {x for x in 'abracadabra' if x not in 'abc'}
字典:
字典推导式: a = {x: x**2 for x in (2, 4, 6)}
遍历两个或更多的序列,可以使用 zip() 组合:
for q, a in zip(questions, answers):
print('What is your {0}? It is {1}.'.format(q, a))
反向遍历一个序列:
for i in reversed(range(1, 10, 2)):
print(i)
按顺序遍历一个序列:
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
print(f)
模块: 包含所有你定义的函数和变量的文件,其后缀名是.py, import 语句: import module1[, module2[,... moduleN]
导入模块: 在 python 用 import 或者 from...import 来导入相应的模块
将整个模块(somemodule)导入,格式为: import somemodule, 调用某个函数:import sys, 写法:sys.path
从某个模块中导入某个函数,格式为: from somemodule import somefunction, 调用某个函数:from sys import argv,path, 写法:path
从某个模块中导入多个函数,格式为: from somemodule import firstfunc, secondfunc, thirdfunc
将某个模块中的全部函数导入,格式为: from somemodule import *
__name__属性:
一个模块被另一个程序第一次引入时,其主程序将运行
每个模块都有一个__name__属性,当其值是'__main__'时,表明该模块自身在运行,否则是被引入:__name__ 与 __main__ 底下是双下划线
dir() 函数: dir(sys)
内置的函数 dir() 可以找到模块内定义的所有名称。以一个字符串列表的形式返回
如果没有给定参数,那么 dir() 函数会罗列出当前定义的所有名称
输入和输出:
将输出的值转成字符串,可以使用 repr() 或 str() 函数来实现:
str(): 函数返回一个用户易读的表达形式
repr(): 产生一个解释器易读的表达形式
input():输入函数,类型为字符串
print():输出函数,类型为字符串
Print 输出: 默认输出是换行的,如果要实现不换行需要在变量末尾加上 end="可以加填充字符如,",如:print( x, end=" " )
str.format() 的基本使用: print('{}网址: "{}!"'.format('百度', 'www.baidu.com'))
字符串中括号及其里面的字符 (称作格式化字段) 将会被 format() 中的参数替换
print("请输入字符{:.2f}F".format(var)): {:.2f}表示将变量var填充到这个位置时取小数点后2位
print('{1} 和 {0}'.format('Google', 'baidu')): 在括号中的数字用于指向传入对象在 format() 中的位置
print('{name}网址: {site}'.format(name='百度', site='www.baidu.com')): 如果在 format() 中使用了关键字参数, 那么它们的值会指向使用该名字的参数
print("{!r}".format('baidu')): !a (使用 ascii()), !s (使用 str()) 和 !r (使用 repr()) 可以用于在格式化某个值之前对其进行转化
读和写文件:
open() 将会返回一个 file 对象: open(filename, mode):
使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法
完整的语法格式为:open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
filename:必需,文件路径(相对或者绝对路径)
mode:可选,文件打开模式:只读,写入,追加等, 默认文件访问模式为只读(r)
buffering: 设置缓冲
encoding: 一般使用utf8
errors: 报错级别
newline: 区分换行符
closefd: 传入的file参数类型
opener:
with 语句: 保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法,如下没有执行关闭文件对象
with open("myfile.txt") as f:
for line in f:
print(line, end="")
代码执行完毕后,就算在处理过程中出问题了,文件 f 总是会关闭, 不会抛出异常
f.name : 文件名称
f.write( "写入内容:Python 是一个非常好的语言。\n是的,的确非常好!!\n" ): print(f.write(string)) >>> 返回写入的字符数
若要写入一些不是字符串的东西, 那么将需要先进行转换
value = ('baidu', 14)
s = str(value)
f.write(s) >>> 输出:('baidu', 14)
file.writelines(sequence): 向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符
seq = ["百度 1\n", "谷歌"]
file.writelines(seq) >>> 换行输出:百度
谷歌
f.read(): print(f.read()): 读取文件内容, 可以指定读取的字符数 >>> print(r.read(5)), 未给定或为负则读取所有
f.readline(): 从文件中读取单独的一行, 包括换行符 '\n', f.readline() 如果返回一个空字符串, 说明已经已经读取到最后一行
f.readlines(): 返回该文件中包含的所有行
f.tell(): 返回文件对象当前所处的位置, 它是从文件开头开始算起的字节数
f.seek(): 改变文件当前的位置, 可以使用 f.seek(offset, from_what) 函数
from_what 的值, 如果是 0 表示开头, 如果是 1 表示当前位置, 2 表示文件的结尾
seek(x,0) : 从起始位置即文件首行首字符开始移动 x 个字符
seek(x,1) : 表示从当前位置往后移动x个字符
seek(-x,2):表示从文件的结尾往前移动x个字符
file.flush(): 刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入
f.close(): 关闭文件并释放系统的资源,如果尝试再调用该文件,则会抛出异常
pickle 模块:
实现了基本的数据序列和反序列化: pickle.dump(obj, file, [,protocol])
mode:
t 文本模式 (默认)。
x 写模式,新建一个文件,如果该文件已存在则会报错。
b 二进制模式。
+ 打开一个文件进行更新(可读可写)。
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写
OS 文件/目录
os.access(path, mode): 检验权限模式
path -- 要用来检测是否有访问权限的路径。
mode -- mode为F_OK,测试存在的路径,或者它可以是包含R_OK, W_OK和X_OK或者R_OK, W_OK和X_OK其中之一或者更多。
os.F_OK: 作为access()的mode参数,测试path是否存在。
os.R_OK: 包含在access()的mode参数中 , 测试path是否可读。
os.W_OK 包含在access()的mode参数中 , 测试path是否可写。
os.X_OK 包含在access()的mode参数中 ,测试path是否可执行。
os.chdir(path): 改变当前工作目录到指定的路径
path -- 要切换到的新路径。
os.chmod(path, mode): 用于更改文件或目录的权限
path -- 文件名路径或目录路径。
flags -- 可用以下选项按位或操作生成, 目录的读权限表示可以获取目录里文件名列表, ,执行权限表示可以把工作目录切换到此目录, 删除添加目录里的文件必须同时有写和执行权限 ,文件权限以用户id->组id->其它顺序检验,最先匹配的允许或禁止权限被应用
stat.S_IXOTH: 其他用户有执行权0o001
stat.S_IWOTH: 其他用户有写权限0o002
stat.S_IROTH: 其他用户有读权限0o004
stat.S_IRWXO: 其他用户有全部权限(权限掩码)0o007
stat.S_IXGRP: 组用户有执行权限0o010
stat.S_IWGRP: 组用户有写权限0o020
stat.S_IRGRP: 组用户有读权限0o040
stat.S_IRWXG: 组用户有全部权限(权限掩码)0o070
stat.S_IXUSR: 拥有者具有执行权限0o100
stat.S_IWUSR: 拥有者具有写权限0o200
stat.S_IRUSR: 拥有者具有读权限0o400
stat.S_IRWXU: 拥有者有全部权限(权限掩码)0o700
stat.S_ISVTX: 目录里文件目录只有拥有者才可删除更改0o1000
stat.S_ISGID: 执行此文件其进程有效组为文件所在组0o2000
stat.S_ISUID: 执行此文件其进程有效用户为文件所有者0o4000
stat.S_IREAD: windows下设为只读
stat.S_IWRITE: windows下取消只读
os.chown(path, uid, gid): 更改文件所有者,如果不修改可以设置为 -1, 你需要超级用户权限来执行权限修改操作
path -- 设置权限的文件路径
uid -- 所属用户 ID
gid -- 所属用户组 ID
os.mkdir(path, mode): 用于以数字权限模式创建目录。默认的模式为 0777 (八进制)
path -- 要创建的目录
mode -- 要为目录设置的权限数字模式
os.open(file, flags[, mode]): 用于打开一个文件,并且设置需要的打开选项,模式参数mode参数是可选的,默认为 0777
file -- 要打开的文件
flags -- 该参数可以是以下选项,多个使用 "|" 隔开:
os.O_RDONLY: 以只读的方式打开
os.O_WRONLY: 以只写的方式打开
os.O_RDWR : 以读写的方式打开
os.O_NONBLOCK: 打开时不阻塞
os.O_APPEND: 以追加的方式打开
os.O_CREAT: 创建并打开一个新文件
os.O_TRUNC: 打开一个文件并截断它的长度为零(必须有写权限)
os.O_EXCL: 如果指定的文件存在,返回错误
os.O_SHLOCK: 自动获取共享锁
os.O_EXLOCK: 自动获取独立锁
os.O_DIRECT: 消除或减少缓存效果
os.O_FSYNC : 同步写入
os.O_NOFOLLOW: 不追踪软链接
os.read(fd, n): 从文件描述符 fd 中读取最多 n 个字节,返回包含读取字节的字符串,文件描述符 fd对应文件已达到结尾, 返回一个空字符串
fd -- 文件描述符
n -- 读取的字节
os.remove(path):删除路径为path的文件。如果path 是一个文件夹,将抛出OSError; 查看下面的rmdir()删除一个 directory
os.rmdir(path):删除path指定的空目录,如果目录非空,则抛出一个OSError异常
os.removedirs(path):递归删除目录
os.rename(src, dst): 重命名文件或目录,从 src 到 dst
src -- 要修改的目录名
dst -- 修改后的目录名
...
语法错误和异常:
语法错误或者称之为解析错
异常:语法是正确的,在运行它的时候,也有可能发生错误
try/except 语句:
首先,执行 try 子句(在关键字 try 和关键字 except 之间的语句), 如果没有异常发生,忽略 except 子句,try 子句执行后结束
如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行
如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中
一个 try 语句可能包含多个except子句,分别来处理不同的特定的异常。最多只有一个分支会被执行
一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组
异常处理并不仅仅处理那些直接发生在 try 子句中的异常,而且还能处理子句中调用的函数(甚至间接调用的函数)里抛出的异常
如果一个异常在 try 子句里(或者在 except 和 else 子句里)被抛出,而又没有任何的 except 把它截住,那么这个异常会在 finally 子句执行后被抛出
except子句可以忽略异常的名称,它将被当作通配符使用。如果你只想知道这是否抛出了一个异常,并不想去处理它,raise 语句就可以再次把它抛出
except:
print("Unexpected error:", sys.exc_info()[0])
raise
try/except...else:
else 子句必须放在所有的 except 子句之后
else 子句将在 try 子句没有发生任何异常的时候执行
try-finally 语句:
无论是否发生异常都将执行最后的代码
用户自定义异常: 通过创建一个新的异常类来拥有自己的异常。异常类继承自 Exception 类,可以直接继承,或者间接继承
assert(断言): 用于判断一个表达式,在表达式条件为 false 的时候触发异常
断言可以在条件不满足程序运行的情况下直接返回错误,而不必等待程序运行后出现崩溃的情况
语法: assert expression 等价于 if not expression: raise AssertionError
raise关键字: raise [Exception [, args [, traceback]]]
显示地引发异常。一旦执行了raise语句,raise后面的语句将不能执行
raise 语句可以抛出一个指定的异常: raise Exception("抛出指定异常:ValueError")
面向对象:
类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
方法:类中定义的函数。
类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
局部变量:定义在方法中的变量,只作用于当前实例的类。
实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
实例化:创建一个类的实例,类的具体对象。
对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
类方法:
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self, 也可以自定义, 实例化时self不需要传参
构造方法: 类的构造方法用__init__(self)定义, 区别与类的方法
无参构造方法:def __init__(self),
带参构造方法:def __init__(self, var1, var2, ...):
构造方法没有返回值
类定义了 __init__() 方法,类实例化时自动调用 __init__() 方法, 不需要显示调用构造方法
构造方法可以有参数,参数通过 __init__() 传递到类的实例化操作上: x = classA(3.0, -4.5)
继承:
单继承写法: class ClassName(BaseClassName):或 class ClassName(modname.BaseClassName):
多继承写法:class ClassName(Base1, Base2, Base3):
若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索, 即方法在子类中未找到时,从左到右查找父类中是否包含方法
方法重写:
在子类重写父类的方法
super() 函数是用于调用父类(超类)的一个方法: super(type[, object-or-type])
type -- 类。
object-or-type -- 类,一般是 self
Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx
类属性与方法:
类的私有属性:
两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问
在类内部的方法中使用时 self.__private_attrs
类的方法:
与一般函数定义不同,类方法必须包含参数 self,且为第一个参数,self 代表的是类的实例
self 的名字并不是规定死的,也可以使用 this,但是最好还是按照约定是用 self
类的私有方法:
两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods
类的专有方法:
__init__ : 构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 函数调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__truediv__: 除运算
__mod__: 求余运算
__pow__: 乘方
命名空间和作用域:
命名空间:
是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的
内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等
全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量
局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
命名空间查找顺序:
局部的命名空间去 -> 全局命名空间 -> 内置命名空间
如果找不到变量var,它将放弃查找并引发一个 NameError 异常
生命周期:
取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束, 因此,我们无法从外部命名空间访问内部命名空间的对象
作用域:
就是一个 Python 程序可以直接访问命名空间的正文区域
在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误
变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称:
L(Local):最内层,包含局部变量,比如一个函数/方法内部。
E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,
那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
G(Global):当前脚本的最外层,比如当前模块的全局变量。
B(Built-in): 包含了内建的变量/关键字等。,最后被搜索
规则顺序: L –> E –> G –> B
内置作用域是通过一个名为 builtin 的标准模块来实现的,但是这个变量名自身并没有放入内置作用域内,所以必须导入这个文件才能够使用它
在Python3.0中,可以使用以下的代码来查看到底预定义了哪些变量:
>>> import builtins
>>> dir(builtins)
Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问
方法内的局部变量要使用全局变量,得通过方法传递参数使用全局变量:
>>> a=1
>>> def test(a): a = a + 1
全局变量和局部变量:
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域
局部变量只能在其被声明的函数内部访问
全局变量可以在整个程序范围内访问
global 和 nonlocal关键字:
内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字
global用来修改全局作用域, nonlocal用来修改嵌套作用域(enclosing 作用域,外层非全局作用域)