Python 是一门解释型语言,无需编译和链接

Python 解释器

交互模式

脚本模式

源码编码

默认情况下,Python 源文件是 UTF-8 编码

指定源文件的字符编码

# -*- coding:utf-8 -*-注释,#注释 及"""注释"""

数据结构

标准数据类型

ython3 中有六个标准的数据类型:Number(数字)

String(字符串)

List(列表)

Tuple(元组)

Set(集合)

Dictionary(字典)

Python3 的六个标准数据类型中:不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组);

可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。

数字(Number)

Python3 支持 int、float、bool、complex(复数)

整数类型是 int,带有小数部分的数字类型是 float

使用 / 运算符返回浮点数,使用 //运算符返回整数

变量在使用前必须 “定义”(赋值),否则会出错

浮点数有完整的支持;整数和浮点数的混合计算中,整数会被转换为浮点数

交互模式中,最近一个表达式的值赋给变量_

数字型变量对于用户是只读的,再次赋值只会创建独立的同名变量

字符串(String)

用单引号 ('...') 或双引号 ("...") 标识字符串,效果相同

\可以用来转义引号

在交互式解释器中,输出的字符串会用引号引起来,特殊字符会用反斜杠转义

在第一个引号前面加上一个r ,可获取原始字符串

字符串文本能够分成多行,使用三引号:"""..."""或者'''...''',

行尾换行符会被自动包含到字符串中,可以在行尾加上\来避免这个行为

字符串可以由+操作符连接(粘到一起),可以由*表示重复

相邻的两个字符串文本自动连接在一起,只用于两个字符串文本,不能用于字符串表达式

Python没有单独的字符类型;一个字符就是一个简单的长度为1的字符串

字符串可以被截取(检索),索引值以 0 为开始值,-1 为从末尾的开始位置

注意 -0 实际上就是 0,所以它不会导致从右边开始计算

字符串支持切片

索引用于获得单个字符,切片让你获得一个子字符串

注意,包含起始的字符,不包含末尾的字符。这使得s[:i] + s[i:]永远等于s

切片的索引有非常有用的默认值;省略的第一个索引默认为零,省略的第二个索引默认为切片的字符串的大小

切片的工作方式:切片时的索引是在两个字符之间

左边第一个字符的索引为 0,而长度为n的字符串其最后一个字符的右界索引为n

+---+---+---+---+---+---+

| P | y | t | h | o | n |

+---+---+---+---+---+---+

0 1 2 3 4 5 6-6 -5 -4 -3 -2 -1对于非负索引,如果上下都在边界内,切片长度就是两个索引之差

试图使用太大的索引会导致错误

一个过大的索引值(即下标值大于字符串实际长度)将被字符串实际长度所代替,

当上边界比下边界大时(即切片左值大于右值)就返回空字符串

Python字符串不可以被更改,它们是不可变的;赋值给字符串索引的位置会导致错误

内置函数len()返回字符串长度

特殊字符例如\n在单引号('...')和双引号("...")中具有相同的含义。

两者唯一的区别是在单引号中,你不需要转义"(但你必须转义\')

列表(List)

列表时括号之间的一列逗号分隔的值

列表的元素不必是同一类型

列表可以被索引和切片,所有的切片操作都会返回一个包含请求的元素的新列表

列表支持连接操作

列表是可变的,允许修改元素

可以对切片赋值,此操作可以改变列表的尺寸,或清空它

内置函数len()同样适用于列表

允许嵌套列表(创建一个包含其它列表的列表)

在列表的末尾添加新的元素,append(x)

在指定位置插入一个元素。第一个参数是准备插入到其前面的那个元素的索引,list.insert(i,x)

删除列表中值为x的第一个元素,list.remove(x);如果没有这样的元素,就会返回一个错误

从列表的指定位置删除元素,并将其返回,list.pop([i]);如果没有指定索引,a.pop()返回最后一个元素

从列表中删除所有元素,list.clear()

返回列表中第一个值为x的元素的索引,list.index(x);如果没有匹配的元素就会返回一个错误

返回x在列表中出现的次数,list.count(x);

对列表中的元素就地进行排序,list.sort()

就地倒排列表中的元素,list.reverse()

返回列表的一个浅拷贝,list.copy();等同于a[:]

将一个给定列表中的所有元素都添加到另一个列表中,list.extend(L)

把列表当作堆栈使用

堆栈作为特定的数据结构,最先进入的元素最后一个被释放(后进先出)

用append()方法可以把一个元素添加到堆栈顶。用不指定索引的pop()方法可以把一个元素从堆栈顶释放出来

把列表当作队列使用

队列作为特定的数据结构,最先进入的元素最先释放(先进先出)

不过,列表这样用效率不高。相对来说从列表末尾添加和弹出很快;在头部插入和弹出很慢(因为,为了一个元素,要移动整个列表中的所有元素)

要实现队列,使用collections.deque,它为在首尾两端快速插入和删除而设计

列表推导式

列表推导式由包含一个表达式的括号组成,表达式后面跟随一个for子句,之后可以有零或多个for或if子句。结果是一个列表,由表达式依据其后面的for和if子句上下文计算而来的结果构成

列表推导式为从序列中创建列表提供了一个简单的方法

squares x ()squares.append(x)注意这个 for 循环中的被创建(或被重写)的名为x的变量在循环完毕后依然存在

squares xx ()列表推导式可使用复杂的表达式和嵌套函数

嵌套的列表推导式

列表解析中的第一个表达式可以是任何表达式,包括列表解析

del语句

从列表中按给定的索引而不是值来删除一个子项:del语句

不同于有返回值的pop()方法,语句del可以从列表中删除切片或清空整个列表

del也可以删除整个变量

元组

一个元组由数个逗号分隔的值组成

元组在输出时总是有括号的,以便于正确表达嵌套结构。

在输入时可以有或没有括号,不过经常括号都是必须的(如果元组是一个更大的表达式的一部分)

不能给元组的一个独立的元素赋值(尽管你可以通过联接和切割来模拟)。

可以创建包含可变对象的元组,例如列表

元组有很多用途。例如 (x, y) 坐标对,数据库中的员工记录等等。

元组就像字符串,不可变的。

通常包含不同种类的元素并通过分拆(参阅本节后面的内容) 或索引访问(如果是namedtuples,甚至可以通过属性)

一对空的括号可以创建空元组;empty=()

要创建一个单元素元组可以在值后面跟一个逗号:singleton='hello',

(在括号中放入一个单值不够明确)

集合

集合是一个无序不重复元素的集

基本功能包括关系测试和消除重复元素

大括号或set()函数可以用来创建集合

创建空集合,你必须使用set()而不是{},后者用于创建空字典

集合推导式语法,a={xforxin'abracadabra'ifxnotin'abc'}

字典

字典在某些语言中可能称为 联合内存 ( associative memories )或 联合数组 ( associative arrays )

字典以关键字为索引,关键字可以是任意不可变类型,通常用字符串或数值

理解字典的最佳方式是把它看做无序的键:值对(key:value 对)集合,键必须是互不相同的(在同一个字典之内)

一对大括号创建一个空的字典:{}

初始化列表时,在大括号内放置一组逗号分隔的键:值对,这也是字典输出的方式

字典的主要操作是依据键来存储和析取值

可以用del来删除键:值对(key:value)

用一个已经存在的关键字存储值,以前为该关键字分配的值就会被遗忘

试图从一个不存在的键中取值会导致错误。

对一个字典执行list(d.keys())将返回一个字典中所有关键字组成的无序列表

如果你想要排序,只需使用sorted(d.keys())

使用in关键字(指Python语法)可以检查字典中是否存在某个关键字(指字典)

dict()构造函数可以直接从 key-value 对中创建字典dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])

字典推导式可以从任意的键值表达式中创建字

如果关键字都是简单的字符串,有时通过关键字参数指定 key-value 对更为方便

dict(sape=4139, guido=4127, jack=4098)

循环技巧

在字典中循环时,关键字和对应的值可以使用items()方法同时解读出来:

knights = {'gallahad': 'the pure', 'robin': 'the brave'}for k, v in knights.items():    print(k,v)

在序列中循环时,索引位置和对应值可以使用enumerate()函数同时得到

for i, v in enumerate(['tic', 'tac', 'toe']):    print(i,v)

同时循环两个或更多的序列,可以使用zip()整体打包:

questions = ['name', 'quest', 'favorite color']answers = ['lancelot', 'the holy grail', 'blue']for q, a in zip(questions, answers):    print('What is your{0}?  It is{1}.'.format(q,a))

需要逆向循环序列的话,先正向定位序列,然后调用reversed()函数:

for i in reversed(range(1, 10, 2)):    print(i)

要按排序后的顺序循环序列的话,使用sorted()函数,它不改动原序列,而是生成一个新的已排序的序列:

basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']for f in sorted(set(basket)):    print(f)

若要在循环内部修改正在遍历的序列(例如复制某些元素),建议您首先制作副本。在序列上循环不会隐式地创建副本。切片表示法使这尤其方便:

words = ['cat', 'window', 'defenestrate']for w in words[:]: # Loop over a slice copy of the entire list.if len(w) > 6:words.insert(0, w)

深入条件控制

while和if语句中使用的条件不仅可以使用比较,而且可以包含任意的操作

比较操作符in和not in审核值是否在一个区间之内

操作符is和is not比较两个对象是否相同

所有的比较操作符具有相同的优先级,低于所有的数值操作

比较操作可以传递。例如a

比较操作可以通过逻辑操作符and和or组合,比较的结果可以用not来取反义

逻辑操作符and和or也称作短路操作符,它们的参数从左向右解析,一旦结果可以确定就停止

如果A和C为真而B为假,A and B and C不会解析C

作用于一个普通的非逻辑值时,短路操作符的返回值通常是最后一个变量

可以把比较或其它逻辑表达式的返回值赋给一个变量

需要注意的是 Python 与 C 不同,在表达式内部不能赋值

比较序列和其它类型

序列对象可以与相同类型的其它对象比较

比较操作按字典序进行:首先比较前两个元素,如果不同,就决定了比较的结果;如果相同,就比较后两个元素,依此类推,直到所有序列都完成比较

如果两个元素本身就是同样类 型的序列,就递归字典序比较。如果两个序列的所有子项都相等,就认为序列相等

如果一个序列是另一个序列的初始子序列,较短的一个序列就小于另一个

字符串的字典序按照单字符的 ASCII 顺序

需要注意的是如果通过比较的对象只要具有合适的比较方法就是合法的

控制流程

if 语句

if…elif…elif… 序列用于替代其它语言中的switch或case语句

Python 的for语句依据任意序列(链表或字符串)中的子项,按它们在序列中的顺序来进行迭代

(通常的循环可能会依据一个等差数值步进过程(如 Pascal),或由用户来定义迭代步骤和中止条件)

在迭代过程中修改迭代序列不安全(只有在使用链表这样的可变序列时才会有这样的情况)

如果你需要一个数值序列,内置函数range()会很方便,它生成一个等差级数链表:

for i in range(5):    print(i)

range(10)生成了一个包含 10 个值的链表,它用链表的索引值填充了这个长度为 10 的列表,所生成的链表中不包括范围中的结束值。也可以让range()操作从另一个数值开始,或者可以指定一个不同的步进值(甚至是负数,有时这也被称为 “步长”):

range(5, 10)

5 through 9range(0, 10, 3)

0, 3, 6, 9range(-10, -100, -30)

-10, -40, -70

需要迭代链表索引的话,如下所示结合使 用range()和len()

a = ['Mary', 'had', 'a', 'little', 'lamb']for i in range(len(a)):print(i,a[i])

输出

0 Mary1 had2 a3 little4 lamb不过,这种场合可以方便的使用enumerate()

在不同方面 range() 函数返回的对象表现为它是一个列表,但事实上它并不是。当你迭代它时,它是一个能够像期望的序列返回连续项的对象;但为了节省空间,它并不真正构造列表。

我们称此类对象是 可迭代的,即适合作为那些期望从某些东西中获得连续项直到结束的函数或结构的一个目标(参数)。我们已经见过的 for 语句就是这样一个迭代器。list() 函数是另外一个( 迭代器 ),它从可迭代(对象)中创建列表

break语句和 C 中的类似,用于跳出最近的一级for或while循环

循环可以有一个else子句;它在循环迭代完整个列表(对于for)或执行条件为 false (对于while)时执行,但循环被break中止的情况下不会执行

与循环一起使用时,else子句与try语句的else子句比与if语句的具有更多的共同点:try语句的else子句在未出现异常时运行,循环的else子句在未出现break时运行。更多关于try语句和异常的内容,请参见异常处理。

continue语句是从 C 中借鉴来的,它表示循环继续执行下一次迭代,(结束本次循环执行语句,开始下一次循环)

pass语句什么也不做。它用于那些语法上必须要有什么语句,但程序什么也不做的场合

这通常用于创建最小结构的类:

class MyEmptyClass:pass

另一方面,pass可以在创建新代码时用来做函数或控制体的占位符。可以让你在更抽象的级别上思考。pass可以默默的被忽视:

def initlog(*args):    pass# Remember to implement this!

定义函数

关键字def引入了一个函数定义。在其后必须跟有函数名和包括形式参数的圆括号。函数体语句从下一行开始,必须是缩进的

函数体的第一行语句可以是可选的字符串文本,这个字符串是函数的文档字符串,或者称为docstring。

在你的代码中包含 docstrings 是一个好的实践

函数调用会为函数局部变量生成一个新的符号表,所有函数中的变量赋值都是将值存储在局部符号表

变量引用首先在局部符号表中查找,然后是包含函数的局部符号表,然后是全局符号表,最后是内置名字表

全局变量不能在函数中直接赋值(除非用global语句命名),尽管他们可以被引用

函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是传值调用(这里的值总是一个对象 引用 ,而不是该对象的值)。[1]一个函数被另一个函数调用时,一个新的局部符号表在调用过程中被创建

一个函数定义会在当前符号表内引入函数名。函数名指代的值(即函数体)有一个被 Python 解释器认定为用户自定义函数的类型。 这个值可以赋予其他的名字(即变量名),然后它也可以被当做函数使用。这可以作为通用的重命名机制

return语句从函数中返回一个值,不带表达式的return返回None

过程结束后也会返回None

语句result.append(b)称为链表对象result的一个方法。方法是一个“属于”某个对象的函数,它被命名为obj.methodename,这里的obj是某个对象(可能是一个表达式),methodename是某个在该对象类型定义中的方法的命名

不同的类型定义不同的方法。不同类型可能有同样名字的方法,但不会混淆。(当你定义自己的对象类型和方法时,可能会出现这种情况,class的定义方法详见类)

深入 Python 函数定义

在 Python 中,可以定义包含若干参数的函数

默认参数值

最常用的一种形式是为一个或多个参数指定默认值

这个函数可以通过几种不同的方式调用:只给出必要的参数:

ask_ok('Do you really want to quit?')

给出一个可选的参数:

ask_ok('OK to overwrite the file?', 2)

或者给出所有的参数:

ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')

这个例子还介绍了 in 关键字。它测定序列中是否包含某个确定的值。

默认值在函数定义作用域被解析重要警告:默认值只被赋值一次。这使得当默认值是可变对象时会有所不同,比如列表、字典或者大多数类的实例关键字参数函数可以通过关键字参数的形式来调用,形如keyword = value在函数调用中,关键字的参数必须跟随在位置参数的后面。传递的所有关键字参数必须与函数接受的某个参数相匹配 (例如actor不是parrot函数的有效参数),它们的顺序并不重要

任何参数都不可以多次赋值

引入一个形如**name的参数时,它接收一个字典(参见Mapping Types — dict),该字典包含了所有未出现在形式参数列表中的关键字参数

可变参数列表

一个最不常用的选择是可以让函数调用可变个数的参数。这些参数被包装进一个元组

通常,这些可变参数是参数列表中的最后一个,因为它们将把所有的剩余输入参数传递给函数。任何出现在*args后的参数是关键字参数,这意味着,他们只能被用作关键字,而不是位置参数:

参数列表的分拆

当要传递的参数已经是一个列表,但要调用的函数却接受分开一个个的参数值,要把已有的列表拆开来,可以在调用函数时加一个*操作符来自动把参数列表拆开

同样的方式,可以使用**操作符分拆关键字参数为字典

Lambda 形式

通过lambda关键字,可以创建短小的匿名函数

这里有一个函数返回它的两个参数的和:lambda a, b: a+b。 Lambda 形式可以用于任何需要的函数对象。出于语法限制,它们只能有一个单独的表达式。语义上讲,它们只是普通函数定义中的一个语法技巧。类似于嵌套函数定义,lambda 形式可以从外部作用域引用变量

文档字符串

第一行应该是关于对象用途的简介

如果文档字符串有多行,第二行应该空出来,与接下来的详细描述明确分隔

接下来的文档应该有一或多段描述对象的调用约定、边界效应等

Python 的解释器不会从多行的文档字符串中去除缩进,所以必要的时候应当自己清除缩进

第一行之后的第一个非空行决定了整个文档的缩进格式

每一行都不应该有缩进,如果有缩进的话,所有的留白都应该清除掉

函数注解

函数注解是关于用户自定义的函数的完全可选的、随意的元数据信息

注解是以字典形式存储在函数的__annotations__属性中,对函数的其它部分没有任何影响。参数注解(Parameter annotations)是定义在参数名称的冒号后面,紧随着一个用来表示注解的值得表达式。返回注释(Return annotations)是定义在一个->后面,紧随着一个表达式,在冒号与->之间

编码风格

使用 4 空格缩进,而非 TAB

在小缩进(可以嵌套更深)和大缩进(更易读)之间,4空格是一个很好的折中。TAB 引发了一些混乱,最好弃用

折行以确保其不会超过 79 个字符

这有助于小显示器用户阅读,也可以让大显示器能并排显示几个代码文件

使用空行分隔函数和类,以及函数中的大块代码

可能的话,注释独占一行

使用文档字符串

把空格放到操作符两边,以及逗号后面,但是括号里侧不加空格:a=f(1,2)+g(3,4)

统一函数和类命名

推荐类名用驼峰命名, 函数和方法名用小写_和_下划线。总是用self作为方法的第一个参数(关于类和方法的知识详见初识类)

不要使用花哨的编码,如果你的代码的目的是要在国际化环境。Python 的默认情况下,UTF-8,甚至普通的 ASCII 总是工作的最好

同样,也不要使用非 ASCII 字符的标识符,除非是不同语种的会阅读或者维护代码

模块

Python 提供了一个方法可以从文件中获取定义,在脚本或者解释器的一个交互式实例中使用。这样的文件被称为模块;

模块中的定义可以导入到另一个模块或主模块中(在脚本执行时可以调用的变量集位于最高级,并且处于计算器模式)

模块是包括 Python 定义和声明的文件,文件名就是模块名加上.py后缀

模块的模块名(做为一个字符串)可以由全局变量__name__得到

如果打算频繁使用一个函数,你可以将它赋予一个本地变量

fib =fibo.fib

print(fib(500))

深入模块

除了包含函数定义外,模块也可以包含可执行语句,

这些语句一般用来初始化模块。他们仅在第一次被导入的地方执行一次

每个模块都有自己私有的符号表,被模块内所有的函数定义作为全局符号表使用

模块的作者可以在模块内部使用全局变量,而无需担心它与某个用户的全局变量意外冲突

可以使用引用模块函数的表示法访问模块的全局变量,modname.itemname

模块可以导入其他的模块

一个(好的)习惯是将所有的import语句放在模块的开始

被导入的模块名会放入当前模块的全局符号表中

import语句的一个变体直接从被导入的模块中导入命名到本模块的语义表中

fromfibo importfib,fib2

fib(500)这样不会从局域语义表中导入模块名

有种方式可以导入模块中的所有定义,可以导入所有除了以下划线(_)开头的命名

fromfibo import*需要注意的是在实践中往往不鼓励从一个模块或包中使用*导入所有,因为这样会让代码变得很难读

出于性能考虑,每个模块在每个解释器会话中只导入一遍。因此,如果你修改了你的模块,需要重启解释器;或者,如果你就是想交互式的测试这么一个模块,可以用imp.reload()重新加载,例如importimp;imp.reload(modulename)。

作为脚本来执行模块

使用以下方式运行 Python 模块时,模块中的代码便会被执行

python fibo.py 模块中的代码会被执行,就像导入它一样,不过此时__name__被设置为"__main__"。这相当于,如果你在模块后加入如下代码

if__name__ =="__main__":importsys

fib(int(sys.argv[1]))

可以让此文件像作为模块导入时一样作为脚本执行。此代码只有在模块作为 “main” 文件执行时才被调用

通常用来为模块提供一个便于测试的用户接口(将模块作为脚本执行测试需求)

模块的搜索路径

导入一个叫spam的模块时,解释器先在当前目录中搜索名为spam.py的文件。如果没有找到的话,接着会到sys.path变量中给出的目录列表中查找。sys.path变量的初始值来自如下:

输入脚本的目录(当前目录)。

环境变量PYTHONPATH表示的目录列表中搜索

(这和 shell 变量PATH具有一样的语法,即一系列目录名的列表)。

Python 默认安装路径中搜索

在支持符号连接的文件系统中,输入的脚本所在的目录是符号连接指向的目录。 换句话说也就是包含符号链接的目录不会被加到目录搜索路径

解释器由sys.path变量指定的路径目录搜索模块,该变量初始化时默认包含了输入脚本(或者当前目录),PYTHONPATH和安装目录

“编译的” Python 文件

为了加快加载模块的速度,Python 会在__pycache__目录下以module.version.pyc名字缓存每个模块编译后的版本,这里的版本编制了编译后文件的格式。它通常会包含 Python 的版本号

为了减少一个编译模块的大小,你可以在 Python 命令行中使用-O或者-OO。-O参数删除了断言语句,-OO参数删除了断言语句和 __doc__ 字符串。

因为某些程序依赖于这些变量的可用性,你应该只在确定无误的场合使用这一选项。“优化的” 模块有一个 .pyo 后缀而不是 .pyc 后缀。未来的版本可能会改变优化的效果。

来自.pyc文件或.pyo文件中的程序不会比来自.py文件的运行更快;.pyc或.pyo文件只是在它们加载的时候更快一些。

compileall模块可以为指定目录中的所有模块创建.pyc文件(或者使用-O参数创建.pyo文件)。

在 PEP 3147 中有很多关这一部分内容的细节,并且包含了一个决策流程。

标准模块

sys,这个模块内置于所有的 Python 解释器

变量sys.path是解释器模块搜索路径的字符串列表

内置函数dir()用于按模块名搜索模块定义,它返回一个字符串类型的存储列表

无参数调用时,dir()函数返回当前定义的命名

dir()不会列出内置函数和变量名。如果你想列出这些内容,它们在标准模块builtins中定义

包通常是使用用“圆点模块名”的结构化模块命名空间

当导入这个包时,Python 通过sys.path搜索路径查找包含这个包的子目录

用户可以每次只导入包里的特定模块

importsound.effects.echo这样就导入了sound.effects.echo子模块,必需通过完整的名称来引用

sound.effects.echo.echofilter(input,output,delay=0.7,atten=4)

导入包时有一个可以选择的方式

fromsound.effects importecho这样就加载了echo子模块,并且使得它在没有包前缀的情况下也可以使用,所以它可以如下方式调用:

echo.echofilter(input,output,delay=0.7,atten=4)

还有另一种变体用于直接导入函数或变量

fromsound.effects.echo importechofilter这样就又一次加载了echo子模块,但这样就可以直接调用它的echofilter()函数:

echofilter(input,output,delay=0.7,atten=4)

需要注意的是使用frompackageimportitem方式导入包时,这个子项(item)既可以是包中的一个子模块(或一个子包),也可以是包中定义的其它命名,像函数、类或变量

import语句首先核对是否包中有这个子项,如果没有,它假定这是一个模块,并尝试加载它。如果没有找到它,会引发一个ImportError异常

相反,使用类似importitem.subitem.subsubitem这样的语法时,这些子项必须是包,最后的子项可以是包或模块,但不能是前面子项中定义的类、函数或变量

从 * 导入包

给提供一个明确的包索引,

import语句按如下条件进行转换:执行frompackageimport*时,如果包中的__init__.py代码定义了一个名为__all__的列表,就会按照列表中给出的模块名进行导入

__all__ = ["echo", "surround", "reverse"]这意味着fromsound.effectsimport*语句会从sound包中导入以上三个已命名的子模块

如果没有定义__all__,fromsound.effectsimport*语句不会从sound.effects包中导入所有的子模块。无论包中定义多少命名,只能确定的是导入了sound.effects包(可能会运行__init__.py中的初始化代码)以及包中定义的所有命名会随之导入。

尽管某些模块设计为使用import*时它只导出符合某种规范/模式的命名,仍然不建议在生产代码中使用这种写法

记住,fromPackageimportspecific_submodule没有错误!事实上,除非导入的模块需要使用其它包中的同名子模块,否则这是推荐的写法

包内引用

果包中使用了子包结构(就像示例中的sound包),可以按绝对位置从相邻的包中引入子模块。例如,如果sound.filters.vocoder包需要使用sound.effects包中的echo模块,它可以fromsound.Effectsimportecho

可以用这样的形式frommoduleimportname来写显式的相对位置导入。那些显式相对导入用点号标明关联导入当前和上级包

需要注意的是显式或隐式相对位置导入都基于当前模块的命名。因为主模块的名字总是"__main__",Python 应用程序的主模块应该总是用绝对导入

多重目录中的包

包支持一个更为特殊的特性,__path__

在包的__init__.py文件代码执行之前,该变量初始化一个目录名列表。该变量可以修改,它作用于包中的子包和模块的搜索功能

事实上函数定义既是“声明”又是“可执行体”;执行体由函数在模块全局语义表中的命名导入

输入和输出

格式化输出

函数str()用于将值转化为适于人阅读的形式,而repr()转化为供解释器读取的形式

str.rjust()方法,把字符串输出到一列,并通过向左侧填充空格来使其右对齐

str.zfill()它用于向数值的字符串表达左侧填充 0,该函数可以正确理解正负号

print('We are the{}who say "{}!"'.format('knights', 'Ni'))

大括号和其中的字符会被替换成传入str.format()的参数

大括号中的数值指明使用传入str.format()方法的对象中的哪一个

如果在str.format()调用时使用关键字参数,可以通过参数名来引用值

print('This{food}is{adjective}.'.format(food='spam', adjective='absolutely horrible'))

'!a'(应用ascii()),'!s'(应用str())和'!r'(应用repr())可以在格式化之前转换值

importmath

print('The value of PI is approximately {}.'.format(math.pi))print('The value of PI is approximately {!r}.'.format(math.pi))输出

The value of PI is approximately 3.141592653589793.

The value of PI is approximately 3.141592653589793.

在字段后的':'后面加一个整数会限定该字段的最小宽度,这在美化表格时很有用

table ={'Sjoerd':4127,'Jack':4098,'Dcab':7678}forname,phone intable.items():print('{0:10} ==> {1:10d}'.format(name,phone))输出

Sjoerd ==> 4127

Jack ==> 4098

Dcab ==> 7678

旧式的字符串格式化

操作符%也可以用于字符串格式化

print('The value of PI is approximately%5.3f.' % math.pi)

文件读写

函数open()返回文件对象,通常的用法需要两个参数:open(filename,mode)

f = open('workfile', 'w')

错误和异常

语法错误

语法错误,也被称作解析错误

异常

运行期检测到的错误称为异常,并且程序不会无条件的崩溃

异常也有不同的类型

打印错误信息时,异常的类型作为异常的内置名显示

内置的异常列出了内置异常和它们的含义

异常处理

通过编程处理选择的异常是可行的

while True:try:x =int(input("Please enter a number: "))breakexceptValueError:print("Oops! That was no valid number. Try again...")

try语句按如下方式工作。首先,执行try子句 (在try和except关键字之间的部分)。

如果没有异常发生,except子句 在try语句执行完毕后就被忽略了。

如果在 try 子句执行过程中发生了异常,那么该子句其余的部分就会被忽略。

如果异常匹配于except关键字后面指定的异常类型,就执行对应的except子句。然后继续执行try语句之后的代码。

如果发生了一个异常,在except子句中没有与之匹配的分支,它就会传递到上一级try语句中。

如果最终仍找不到对应的处理语句,它就成为一个未处理异常,终止程序运行,显示提示信息。一个try语句可能包含多个 except 子句,分别指定处理不同的异常

try…except语句可以带有一个else子句,该子句只能出现在所有 except 子句之后。当 try 语句没有抛出异常时,需要执行一些代码,可以使用这个子句

在异常名(列表)之后,也可以为 except 子句指定一个变量。这个变量绑定于一个异常实例,它存储在instance.args的参数中

抛出异常

raise语句允许程序员强制抛出一个指定的异常

用户自定义异常

在程序中可以通过创建新的异常类型来命名自己的异常

异常类通常应该直接或间接的从Exception类派生

定义清理行为

不管有没有发生异常,finally子句在程序离开try后都一定会被执行。当try语句中发生了未被except捕获的异常(或者它发生在except或else子句中),在finally子句执行完后它会被重新抛出。try语句经由break,continue或return语句退 出也一样会执行finally子句

预定义清理行为

Python 的类机制通过最小的新语法和语义在语言中实现了类。

它是 C++ 或者 Modula-3 语言中类机制的混合

类的大多数重要特性都被完整的保留下来:类继承机制允许多重继承,派生类可以覆盖(override)基类中的任何方法或类,可以使用相同的方法名称调用基类的方法。对象可以包含任意数量的私有数据

Python 作用域和命名空间

命名空间是从命名到对象的映射

当前命名空间主要是通过 Python 字典实现的,不过通常不关心具体的实现方式

不同命名空间中的命名没有任何联系,用户必须以模块名为前缀来引用它们

Python 中任何一个“.”之后的命名为属性,例如,表达式z.real中的real是对象z的一个属性

表达式modname.funcname中,modname是一个模块对象,funcname是它的一个属性

模块的属性和模块中的全局命名有直接的映射关系:它们共享同一命名空间

属性可以是只读过或写的,可写的属性也可以用del语句删除

例如:delmodname.the_answer会从modname对象中删除the_answer属性

不同的命名空间在不同的时刻创建,有不同的生存期

模块的全局命名空间在模块定义被读入时创建,通常,模块命名空间也会一直保存到解释器退出

包含内置命名的命名空间在 Python 解释器启动时创建,会一直保留,不被删除

由解释器在最高层调用执行的语句,不管它是从脚本文件中读入还是来自交互式输入,都是__main__模块的一部分,所以它们也拥有自己的命名空间(内置命名也同样被包含在一个模块中,它被称作builtins)。

当调用函数时,就会为它创建一个局部命名空间,并且在函数返回或抛出一个并没有在函数内部处理的异常时被删除

作用域就是一个 Python 程序可以直接访问命名空间的正文区域。

通常,局部作用域引用当前函数的命名

在函数之外,局部作用域与全局使用域引用同一命名空间:模块命名空间。

类定义也是局部作用域中的另一个命名空间。

一个定义于某模块中的函数的全局作用域是该模块的命名空间,而不是该函数的别名被定义或调用的位置

如果没有使用global语法,其赋值操作总是在最里层的作用域。赋值不会复制数据,只是将命名绑定到对象

特别是import语句和函数定义将模块名或函数绑定于局部作用域(可以使用global语句将变量引入到全局作用域)。

global语句用以指明某个特定的变量为全局作用域,并重新绑定它。

nonlocal语句用以指明某个特定的变量为封闭作用域,并重新绑定它

类定义语法

类的定义就像函数定义(def语句),要先执行才能生效

classClassName:.

.

.

进入类定义部分后,会创建出一个新的命名空间,作为局部作用域,所有的赋值成为这个新命名空间的局部变量。特别是函数定义在此绑定了新的命名

类定义完成时(正常退出),就创建了一个类对象

原始的局部作用域(类定义引入之前生效的那个)得到恢复,类对象在这里绑定到类定义头部的类名(

类对象

类对象支持两种操作:属性引用和实例化

属性引用使用和 Python 中所有的属性引用一样的标准语法:obj.name。类对象创建后,类命名空间中所有的命名都是有效属性名

__doc__也是一个有效的属性,返回类的文档字符串

类的实例化使用函数符号,只要将类对象看作是一个返回新的类实例的无参数函数即可

x =MyClass()以上创建了一个新的类实例并将该对象赋给局部变量x

很多类都倾向于将对象创建为有初始状态的。因此类可能会定义一个名为__init__()的特殊方法

def__init__(self):self.data = []

类定义了__init__()方法的话,类的实例化操作会自动为新创建的类实例调用__init__()方法

__init__()方法可以有参数,参数通过__init__()传递到类的实例化操作上

classComplex:def__init__(self,realpart,imagpart):self.r =realpart

self.i =imagpart

x =Complex(3.0,-4.5)x.r,x.i

实例对象

实例对象唯一可用的操作就是属性引用

和局部变量一样,数据属性不需要声明,第一次使用时它们就会生成。

另一种为实例对象所接受的引用属性是方法。方法是“属于”一个对象的函数

实例对象的有效名称依赖于它的类

按照定义,类中所有(用户定义)的函数对象对应它的实例中的方法

方法对象

通常,方法通过右绑定方式调用,x.f()

方法的特别之处在于实例对象作为函数的第一个参数传给了函数

通常,以n个参数的列表去调用一个方法就相当于将方法的对象插入到参数列表的最前面后,以这个列表去调用相应的函数

引用非数据属性的实例属性时,会搜索它的类。如果这个命名确认为一个有效的函数对象类属性,就会将实例对象和函数对象封装进一个抽象对象:这就是方法对象

以一个参数列表调用方法对象时,它被重新拆封,用实例对象和原始的参数列表构造一个新的参数列表,然后函数对象调用这个新的参数列表

类和实例变量

一般来说,实例变量用于对每一个实例都是唯一的数据,类变量用于类的所有实例共享的属性和方法

一些说明

数据属性会覆盖同名的方法属性

大写方法名称的首字母,使用一个唯一的小字符串(也许只是一个下划线)作为数据属性名称的前缀,或者方法使用动词而数据属性使用名词

数据属性可以被方法引用,也可以由一个对象的普通用户(客户)使用

换句话说,类不能用来实现纯净的数据类型

事实上,Python 中不可能强制隐藏数据

命名约定可以避免很多麻烦

从方法内部引用数据属性(或其他方法)并没有快捷方式

一般,方法的第一个参数被命名为self。这仅仅是一个约定:对 Python 而言,名称self绝对没有任何特殊含义类属性的任何函数对象都为那个类的实例定义了一个方法

函数定义代码不一定非得定义在类中:也可以将一个函数对象赋值给类中的一个局部变量

方法可以像引用普通的函数那样引用全局命名。与方法关联的全局作用域是包含类定义的模块。

(类本身永远不会做为全局作用域使用

每个值都是一个对象,因此每个值都有一个 类(class) (也称为它的 类型(type) ),它存储为object.__class__

继承

派生类的定义如下所示

classDerivedClassName(BaseClassName):.

.

.

命名BaseClassName(示例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用

classDerivedClassName(modname.BaseClassName):构造派生类对象时,就记住了基类

如果在类中找不到请求调用的属性,就搜索基类。如果基类是由别的类派生而来,这个规则会递归的应用上去

方法引用按如下规则解析:搜索对应的类属性,必要时沿基类链逐级搜索,如果找到了函数对象这个方法引用就是合法的

派生类可能会覆盖其基类的方法。因为方法调用同一个对象中的其它方法时没有特权,基类的方法调用同一个基类的方法时,可能实际上最终调用了派生类中的覆盖方法

派生类中的覆盖方法可能是想要扩充而不是简单的替代基类中的重名方法

Python 有两个用于继承的函数:

函数isinstance()用于检查实例类型:isinstance(obj,int)只有在obj.__class__是int或其它从int继承的类型

函数issubclass()用于检查类继承:issubclass(bool,int)为True,因为bool是int的子类。

然而,issubclass(float,int)为False,因为float不是int的子类

多继承

Python 同样有限的支持多继承形式

classDerivedClassName(Base1,Base2,Base3):.

super()可以动态的改变解析顺序

为了防止重复访问基类,通过动态的线性化算法,每个类都按从左到右的顺序特别指定了顺序,每个祖先类只调用一次,这是单调的(意味着一个类被继承时不会影响它祖先的次序)

私有变量

有一个变通的访问用于大多数 Python 代码:以一个下划线开头的命名(例如_spam)会被处理为 API 的非公开部分(无论它是一个函数、方法或数据成员)。它会被视为一个实现细节,无需公开

name mangling(命名编码)

任何形如__spam的标识(前面至少两个下划线,后面至多一个),被替代为_classname__spam,去掉前导下划线的classname即当前的类名。此语法不关注标识的位置,只要求在类定义内

名称重整是有助于子类重写方法,而不会打破组内的方法调用

classMapping:def__init__(self,iterable):self.items_list = []self.__update(interable)defupdate(self,interable):foritem ininterable:self.items_list.append(item)__update =update

classMappingSubclass(Mapping):defupdate(self,keys,values):foritem inzip(keys,values):self.items_list.append(item)需要注意的是编码规则设计为尽可能的避免冲突,被认作为私有的变量仍然有可能被访问或修改

要注意的是代码传入exec(),eval()时不考虑所调用的类的类名,视其为当前类,这类似于global语句的效应,已经按字节编译的部分也有同样的限制。这也同样作用于getattr(),setattr()和delattr(),像直接引用__dict__一样。

补充

将一组已命名的数据项绑定在一起。一个空的类定义可以很好的实现它

classEmployee:passjohn =Employee()# Create an empty employee record# Fill the fields of the recordjohn.name ='John Doe'john.dept ='computer lab'john.salary =1000实例方法对象也有属性:m.__self__是一个实例方法所属的对象,而m.__func__是这个方法对应的函数对象

异常也是类

用户自定义异常也可以是类。利用这个机制可以创建可扩展的异常体系

以下是两种新的,有效的(语义上的)异常抛出形式,使用raise语句:

raiseClass

raiseInstance

第一种形式中,Class必须是type或其派生类的一个实例。第二种形式是以下形式的简写

raiseClass()

发生的异常其类型如果是except子句中列出的类,或者是其派生类,那么它们就是相符的(反过来说--发生的异常其类型如果是异常子句中列出的类的基类,它们就不相符)

classB(Exception):passclassC(B):passclassD(C):passforcls in[B,C,D]:try:raisecls()exceptD:print("D")exceptC:print("C")exceptB:print("B")

打印一个异常类的错误信息时,先打印类名,然后是一个空格、一个冒号,然后是用内置函数str()将类转换得到的完整字符串

迭代器

大多数容器对象都可以用for遍历:

迭代器的用法在 Python 中普遍而且统一

在后台,for语句在容器对象中调用iter()。该函数返回一个定义了__next__()方法的迭代器对象,它在容器中逐一访问元素。没有后续的元素时,__next__()抛出一个StopIteration异常通知for语句循环结束

给自己的类添加迭代器行为

定义一个__iter__()方法,使其返回一个带有__next__()方法的对象

如果这个类已经定义了__next__(),那么__iter__()只需要返回self:

classReverse:"""Iterator for looping over a sequence backwards."""def__init__(self,data):self.data =data

self.index =len(data)def__iter__(self):returnselfdef__next__(self):ifself.index ==0:raiseStopIterationself.index =self.index -1returnself.data[self.index]

生成器

Generator是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,需要返回数据的时候使用yield语句。每次next()被调用时,生成器回复它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)

defreverse(data):forindex inrange(len(data)-1,-1,-1):yielddata[index]forchar inreverse('golf'):print(char)基于类的迭代器,它能作的每一件事生成器也能作到

因为自动创建了__iter__()和__next__()方法,生成器显得如此简洁

另一个关键的功能在于两次执行之间,局部变量和执行状态都自动的保存下来

除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出StopIteration异常

生成器表达式

有一个例外。模块对象有一个隐秘的只读对象,名为__dict__,它返回用于实现模块命名空间的字典,命名__dict__是一个属性而非全局命名。显然,使用它违反了命名空间实现的抽象原则,应该被严格限制于调试中。

来自

https://www.runoob.com/manual/pythontutorial3/docs/html/appetite.html

python语法详解大全_笔记:Python 语法要点汇总相关推荐

  1. oracle拆分分区语法详解大全_学习笔记:Oracle分区表 添加 删除 合并 删除 交换 拆分等分区表的操作案例...

    天萃荷净 Oracle分区表管理,记录关于Oracle分区表的管理案例:创建.删除.合并.拆分.交换.更改分区表的操作方法 1.添加创建分区表 1.1)增加分区(add partition) 语法是: ...

  2. PyTorch Python API详解大全(持续更新ing...)

    诸神缄默不语-个人CSDN博文目录 具体内容以官方文档为准. 最早更新时间:2021.4.23 最近更新时间:2023.1.9 文章目录 0. 常用入参及函数统一解释 1. torch 1.1 Ten ...

  3. python闭包详解函数_详解python函数的闭包问题(内部函数与外部函数详述)

    python函数的闭包问题(内嵌函数) >>> def func1(): ... print ('func1 running...') ... def func2(): ... pr ...

  4. python绘图颜色代码大全_【python】Matplotlib作图常用marker类型、线型和颜色

    python作图中常常会考虑用什么颜色.marker.线型,这个资料查了又查,所以自己总结在这个地方,以便常用. 一.常用marker表示 1.普通marker 这类普通marker直接marker ...

  5. python算法详解豆瓣_豆瓣爬虫实践-python版

    豆瓣登录,无验证码版: import requests #starturl = "https://www.douban.com/accounts/login" loginurl = ...

  6. python多线程详解_python基础:python多线程详解

    前言 多线程类似于同时执行多个不同程序,多线程运行有如下优点:使用线程可以把占据长时间的程序中的任务放到后台去处理. 用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进 ...

  7. python编写程序解方程_用Python解方程

    我们先从简单的来 例题1: 这是北师大版小学六年级上册课本95页的一道解方程练习题: 大家可以先口算一下,这道题里面的x的值为200 接下来我们用python来实现,代码如下,每一句代码后面都写有解释 ...

  8. python电子相册制作代码大全_用Python和Conky做个电子相册,美化你的Linux桌面

    现在手机的拍照功能日趋强大,每个人电脑上想必都至少有几十个G的照片吧.全打印出来实在是太费钱了.而闲置的旧电脑完全可以利用起来播放这些照片.下面就介绍利用Conky和Python实现随机播放相片的功能 ...

  9. python线性表和队列_[笔记]python数据结构之线性表:linkedlist链表,stack栈,queue队列...

    python数据结构之线性表 python内置了很多高级数据结构,list,dict,tuple,string,set等,在使用的时候十分舒心.但是,如果从一个初学者的角度利用python学习数据结构 ...

最新文章

  1. 网络工程:2.1.ARP协议与PC间通信
  2. 重写enum的valueof方法等
  3. navicat修改sqlserver密码_oracle密码过期
  4. C++ Primer 5th笔记(chap 16 模板和泛型编程)类模板成员函数的实例化
  5. spark RDD的血缘关系
  6. 安装ubuntu 13.04
  7. Condition - Java多线程编程
  8. 【C语言简单说】十九:二维数组循环嵌套(2)
  9. 基于Apache OLTU的OAuth2.0授权解决方案
  10. layout布局_安卓最常见的几种布局
  11. [告知]在评论中发布广告者必删!
  12. iOS内存管理学习笔记二
  13. matlab中emd未定义,EMD的Matlab程序
  14. 学习总结——小程序中输入框和键盘的那些事
  15. 用过的几款步进电机驱动IC
  16. FPGA之通信算法工程师面试题3
  17. python的print函数中file_python3之print()函数
  18. python招聘杭州拉勾网_Python爬虫:爬取拉勾网招聘信息
  19. Java小白常问的问题大全
  20. OSChina 周日乱弹 —— 这个野男人是谁

热门文章

  1. 200多个js技巧代码(4)
  2. DEV—【GridControl添加按钮列】
  3. PHP二分法查找,MYSQL索引即为用了此查找
  4. PHP正则表达式快速学习方法
  5. 8个容易被忽略但不能忽略的SD-WAN功能-Vecloud
  6. SDN架构的本质属性—Vecloud
  7. SD-WAN5年增长率超过40%,为什么越来越受到企业欢迎?
  8. 今天收拾了个电脑抽屉,发现原来我是个有钱人
  9. jQuery获取或设置元素的宽度和高度
  10. 使用阿里云镜像maven管理配置开发环境