Python语法:#Python#
了解
Python语言的概念
Python是一门强大的多范式的计算机编程语言
它以程序员的多产、代码的可读性、软件的高质量开发为目标而不断优化
Python着眼于开发者的生产效率以及软件质量
2.x版本和3.x版本的选择
选用3的情况:新的特性,演化,越来越好
选用2的情况:已有代码,稳定性,做出改动的代价大
同时选用2和3:版本中立的代码
总结:如果你不需要去维护旧的2.x的代码,而且自己具有一定的自学能力,那么最新的python版本就是最好的python版本
为什么使用Python
软件质量
Python更注重可读性、一致性、软件质量,Python代码在设计之初就具有良好的可读性,因此具备了比传统语言更优秀的可重用性和可维护性
开发者生产效率
Python的开发者效率比其他语言提高了数倍,Python的代码更短,调试更少,更易于维护,解释型语言可以立即运行
程序的可移植性
绝大多数的Python程序不作任何改变即可在所有主流计算机平台上运行
标准库的支持
Python内置了众多构建并可移植的功能模块,称为标准库,涵盖了很多方面
组件集成
Python可以通过多种集成机制轻松地与应用程序的其他部分进行通信,这种集成使Python称为实现产品定制和扩展的工具
Python可以调用各种语言各种软件的功能,Python绝不仅仅是一个孤立的工具
与其他语言相比
- 开源,Python开源的本质意味着它不可能被某一个公司所掌控
- 比C、C++、Java、C Sharp 更简单,更易于使用
- 比 Perl、Ruby 更具有可读性,语法简洁连贯
- 比PHP用途更广,更具有跨平台性
Python是不是“脚本语言”?
Python是一门通用型的编程语言,而它时常扮演脚本语言的角色
何谓脚本,其实并没有官方的定义
一般来说,我们把描述简单的顶层代码文件叫做 脚本,而那些相对复杂的多文件应用叫做 程序
python也常常用来替代Shell作为操作系统的工具
可以直接运行的文件往往也叫做脚本(一个顶层程序文件的非正式说法)
import this
运行这个导入,会打印出一个“菜单”,即python的设计理念
Python的缺点是什么
Python的执行速度还不够快
目前Python的标准实现方式是将源代码的语句编译(翻译)为字节码(byte code)的形式,之后再将字节码解释出来
由于字节码是一种与平台无关的格式,因而它具有可移植性
因为python并没有将代码编译为底层的二进制代码,所以一些python程序会比C这样的完全编译型语言要慢
但是记住:
- 程序的类型决定了是否需要关注程序的执行速度
- 开发速度带来的效益往往比执行速度带来的损失更为重要
Python的特性
易于学习
Python编码简单,运行简单,部署也简单
并且提供了众多编译语言才有的高级软件工程工具
Python曾经被称为“可以执行的伪代码”
动态类型
Python在程序运行的过程中跟踪对象的类型,不需要代码中进行复杂的类型和大小的声明
Python中没有类型或变量声明这种做法,因为Python代码不约束数据的类型,它往往自动地应用了一种广义上的对象
自动内存管理
Python自动为对象分配空间,并且当对象不再使用时将自动撤销空间(“垃圾回收”)
在标准Python中(也叫CPython),一旦一个对象的最后一次引用被移除,空间将会立即回收
当需要是自动扩展或收缩
即:Python能够帮助你完成底层的内存管理
内置对象类型、内置工具、标准库
列表、元组、字典、集合
模块、类、异常
以及众多的标准库
Python预置的众多工具可以让我们编程更加轻松
超级丰富的第三方库
互联网上的各个都是人才!
可混合编程(“胶水语言”)
python可以调用许多语言的功能,也可以被许多语言去调用(本质在于python的解释器可以被其他语言实现)
这让python的功能丰富了很多,在python解决不了的时候,可以将其他语言的功能拿过来使用
Python的应用现状
暂略
Python命名的由来
英国喜剧组“Monty Python”是python命名的由来,python的作者是他们的粉丝
Python是工程,不是艺术
Python 程序执行过程(解释器)
解释器简介
从Python目前的实现来讲,你写了Python的代码,要运行,就必须找一个Python的解释器
Python解释器是一个程序或软件,可以让Python的代码运行起来(就是你去下载安装的Python)
/ma
具体运行一个程序的流程是这样的:
- 你写了一段Python代码
- Python的解释器读取这段代码
- Python解释器翻译你写的代码,变成计算机可以执行的二进制代码
- Python解释器将翻译后的二进制代码交给计算机执行
实际上,解释器是代码与机器的计算机硬件之间的软件逻辑层
当Python安装在电脑上之后,它会生成一些组件:至少包括一个解释器、一套支持库
Python解释器可能采取可执行程序的形式,或是作为链接到另一个程序的一系列支持库
根据实现Python解释器的方式的不同,具体情况会有所不同。目前最常用的是C语言实现的Python解释器,即 “CPython”
无论采用何种形式,编写的Python代码必须在解释器中运行,也就是要先安装Python解释器才能运行Python代码
程序如何执行
程序员的视角
考虑最简单的形式,一个Python程序是一个包含Python语句的文本文件(后缀名 .py 是可选的,从技术上来讲,.py后缀名只要在被“导入”时才是必须的)
当你把Python语句输入到文本文件之后,你必须告诉Python解释器来执行这个文件,也就是解释这个文件中的Python代码(你不说要执行,Python解释器是不会自动帮你执行的哈)
告诉解释器执行一般有两种方式:
- 以 Python.exe 的打开方式打开运行这个文本文件
- 在命令行使用 python 文件名 的方式来解释这个文件中的代码
Python的视角
除了,编写代码,交给解释器,解释器执行代码,这个过程之外,透过表面,在Python内部还有一些事情发生
对Python运行时结构有一些基本的了解,可以帮助你从宏观上把握程序的执行
当Python运行脚本时,在代码开始执行之前,Python还会执行一些步骤:
- 编译代码为所谓的“字节码”
- 将“字节码”转发到所谓的“虚拟机”中
字节码编译
执行程序时,Python内部会先将源代码编译成字节码的形式,这里的编译只是一个简单的翻译步骤
字节码:一种低级的、与平台无关的表现形式
即:Python通过把你的代码每一句话分解为单一步骤的一组字节码指令
字节码可以提高执行速度,比直接翻译原始的代码要快得多
.pyc 文件,就是编译过的源代码
如果Python进程在机器上拥有写入权限,那么它会把程序的字节码保存为一个 .pyc 为扩展名的文件,下一次运行程序时,如果上次保存字节码之后没有修改过源代码,并且运行使用的是同一个Python解释器版本,那么Python将会加载.pyc文件并且跳过编译字节码这个步骤
- python检查源文件是否有改变:通过源文件和字节码文件最后一次修改的时间戳,确认它是否必须重新编译,如果修改了源代码,那么下次运行时,字节码将自动重新创建
- Python的版本:导入机制同时检查是否需要因为使用了不同的Python版本而重新编译,这些版本信息在3.2之前保存在字节码文件中,3.2之后保存在字节码文件名中
如果python无法在机器中写入字节码,那么字节码将会在内存中生成,并且在程序结束时被丢弃
字节码只会针对被导入的文件而生成,而不是顶层的执行脚本,严格来说,字节码是一种对导入的优化
文件仅在程序运行时才会被导入
在交互式命令行中输入的命令不会生成字节码
Python虚拟机 PVM
PVM就是迭代运行字节码指令的一个大循环,一个接一个完成操作
PVM 是 Python 的运行时引擎,时常表现为 Python 系统的一部分,并且是实际运行脚本的组件,从技术上讲,它是 Python 解释器的最后一步
PVM 循环仍需要解释字节码!内部仍有编译的步骤
最终导致的效果就是,纯 Python 代码的运行速度介于传统的编译语言和传统的解释语言之间
Python 中真正拥有的只有运行时:完全不需要初始的编译阶段,所有的事情都是在程序运行时发生的
甚至包括建立函数和类的操作以及模块之间的链接(这在静态语言中往往是在执行之前发生的,而在 Python 中是与程序的执行同时进行的)
Python的各种实现
CPython:标准的Python
Jython:基于Java的Python
IronPython:基于 .NET 的Python
Stackless:注重并发的Python
PyPy:注重速度的Python
执行优化工具
Cython:Python和C的混合体
Shed Skin:Python带C++的转换器
Psyco:原先的即时编译器
冻结二进制文件(转换为可以执行的文件)
运行程序的方式
进入和退出交互式命令行
在系统命令行下输入python,即可进入交互式命令行模式(如果不在python目录则需要先配置环境变量)
退出交互式命令行:
- windows 中,
Ctrl + Z
- UNIX 中,
Ctrl + D
PATH 和启动器
在命令行中运行程序
python 代码文件
也可以将输出定向到另一个文件中:python 代码文件 > a.txt
在比较新的 windows 版本上,我们也可以仅仅输入脚本的名字,由于新的 windows 系统使用注册表(文件名关联)找到用哪个程序来运行一个文件,所以我们不需要在命令行上显式地使用 python 来运行一个 .py
文件
指定解释器
在 Python 脚本的第一行,可以用一种特殊的注释来指定使用某个解释器运行这个脚本
#!/...../python
这样,就可以直接运行这个文件了(如果没有可执行权限,需要使用 chmod + x
来赋予权限)
UNIX env 查找技巧
自动寻找Python解释器的路径
env 程序可以通过系统的搜索路径的设置定位 Python 解释器,这种方法可以使代码具有可移植性
#!/usr/bin/env python
为什么会使用交互式命令行模式
代码立即执行,便于实验和测试一些语法特性
这种体验方式不容易带来破坏,要进行真正的破坏,必须显式地导入模块,直接的Python代码总是可以安全运行的
交互式命令行使用
- 只能输入 Python 命令
- 不需要 print 语句,直接输入变量然后回车就可以打印出其值
- 在交互式命令行模式下不需要缩进(目前还不需要)
- 复合语句下(由于不需要缩进),提示符会有变化 ...
- 交互式命令行模式中,用一个空行结束复合语句
- 交互式命令行一次运行一条语句
- 不能在交互式命令行模式中复制并粘贴多行代码,除非这段代码每条复合语句的后面都包含空行!
模块导入与重载
导入同时也是一种启动程序的方法
每一个以扩展名 .py
结尾的 Python 源代码文件都是一个模块
其他文件可以通过导入一个模块读取这个模块定义的内容---导入操作从本质上来讲就是载入另一个文件,并给予读取那个文件内容的权限
一个模块的内容通过其属性从而被外部世界使用
Python 程序架构的一个核心思想,更大的程序往往以多个模块文件的形式出现,并且从其他模块文件导入工具
其中的一个模块文件指定文主文件,或叫做顶层文件,或“脚本”,也就是启动之后能运行整个程序的文件,逐行运行
在这一层之下,全部是模块导入模块
导入操作运行文件中的代码,这个文件作为最后一步正在被加载,正因为如此,导入文件是另一种运行文件的方法
每次会话中,只有第一次导入时会运行模块中的代码,后面的导入不会反映出模块的修改(后面的导入都不起作用),因为导入是一个开销很大的操作
from 语句直接从一个模块中复制出一个名字,属性成为了接收者的直接变量
from 复制出的名字会产生覆盖的问题,并且覆盖的时候不会发出警告!
使用reload函数:
from imp import reload
# 在使用reload重新载入模块之前,需要先成功导入模块
import xxx
reload(xxx)
relaod 函数载入并运行了文件当前版本的代码,如果模块已经修改,那么 reload 会反映出修改的变化
reload 函数必须在成功导入之后才能使用(即 reload 之前,请确保已经成功地导入了这个模块)
reload 是一个函数,import 是一个语句
reload 的返回值:<module 模块名 from 模块路径 >
加载的模块
用一个 from 载入的名字不会通过一个 reload 直接更新,但是用一条 import 语句访问的名字会
reload 不可传递,重载一个模块文件不会重载模块所导入的任何模块,所以有时候必须重载多个文件
Python2.x中,reload可以作为内置函数使用,因此不需要导入
模块的属性:模块可以看做是一个属性(绑定在特定对象上的变量名)的包(命名空间)
导入操作将会在最后一步执行文件,导入者得到了模块文件中在顶层所定义的所有变量名的访问权限
dir(模块名)
:返回一个包含模块内部全部属性的列表
模块中通常会有一些预置的变量名:通常是 __xxx__
形式,这些变量名对于解释器来说有特殊的意义
模块也是 Python 程序最大的程序结构,Python 程序往往由多个模块文件构成,通过 import 语句连接在一起
每个模块都是自包含的命名空间,一个模块文件不能看到其它文件中定义的变量名,除非显式导入了那个文件
模块文件在代码文件中起到了最小化命名冲突的作用,因为每个文件都是一个独立完备的命名空间,即使拼写相同,一个文件的变量名也不会和另一个文件的变量名冲突
使用exec运行模块文件:exec(open('xxx').read())
exec 调用有着类似 import 的效果,但它并不会真的导入模块,它的操作就好像把模块中的代码 “粘贴” 进来一样
注意这种操作有可能默默地覆盖掉正在使用的变量,而且不会发出提示
Python自带的IDLE环境
IDLE 是 Python 自带的一个 IDE,用来做 Python开发的图形界面程序,可以编辑、运行、浏览、调试 Python程序
IDLE 使用Python内置的 TKinter库进行开发,所以 IDLE也是可移植的
IDLE 只是标准库中模块搜索路径上的一个Python脚本,所以也可以通过Python命令来运行它
python -m idlelib.idle
IDLE 的常用技巧:
- 前一条:Alt + P(Mac:Ctrl + P)
- 后一条:Alt + N(Mac:Ctrl + N)
注意:
- Tkinter GUI 和 线程程序 可能并不适合用 IDLE 来开发,因为IDLE本身使用tkinter开发的,如果用它来开发tkinter程序,可能会没有响应
- 如果发生了连接错误,可以尝试使用单进程模式启动IDLE
基本准则
- 访问不存在的东西,是一种错误
Python对象类型概述
在Python中,数据以对象的形式出现
从本质上看,对象无非就是内存的一部分,包含数值和相关操作的集合
Python脚本中的一切都是对象
Python的程序结构
Python 的程序可以分解为 模块、语句、表达式、对象
- 程序由模块组成
- 模块包含语句
- 语句包含表达式
- 表达式创建并处理对象
为什么要使用内置类型
懒,而且没有必要重复实现常用的类型
- 内置对象使程序更容易编写,不必从零开始
- 内置对象是可以进一步扩展的组件
- 内置对象往往比自己写的数据结构更有效率
- 内置对象是语言标准的一部分
内置函数 type(x)
内置函数type接收一个对象,返回一个type对象,这个对象能告知其他对象的类型
在python3.x中,类型与类已经合并起来了
Python的核心数据类型
数字、字符串、列表、字典、元组、文件、集合
类型、None、布尔
函数、模块、类
已编译的代码、调用栈跟踪
字面量的解释:
- python中,字面量一般理解为那些产生Python对象的表达式,有时候也称为常量
- 注意:常量一次并不意味着对象或者变量具有不可变性
python中没有类型声明,运行的表达式的语法决定了创建和使用的对象的类型
一旦创建了一个对象,它就和操作集合绑定了
数字
数字类型包括:整数、浮点数、复数、固定精度的十进制数、有理分数、等等
python3.x的整数类型会在需要的时候自动提供额外的精度(而在python2.x中,有一个处理大数值的单独的长整型)
字符串
字符串属于序列类型
序列中的元素包含了一个从左到右的顺序,序列中的元素根据它们的相对位置进行存储和读取
序列:一个包含其他对象的有序集合
字符串:有单个字符的字符串所组成的序列
序列的长度:内置函数 len(S)
可以获取序列的长度
fan序列的索引和切片
索引操作:S[index]
,通过索引可以取出序列中的元素
索引的计算规则:
- 从左到右:
0, 1, 2, 3, ......, len(S)-1
- 从右到左:
-1, -2, -3, ......, -len(S)
即:[len(S)+k]
如果k是负数
切片操作:S[start:end:step]
- 从start开始,到end位置,以step为间隔取值,组成一个新的序列
- 包含start,不包含end
step>0
从左到右,step<0
则从右到左
注:切片返回新的对象
序列的操作
序列的运算:
- 加法:序列连接
- 乘法:序列和整数相乘,表示序列重复
- 这里的加法和乘法并不是数学意义上的功能,体现了对象的多态性(即:操作的意义取决于被操作的对象)
in:判断元素是否存在
not in:判断元素不存在(注意是 not in,不是 in not)
其他:
len(s)
:获取序列的长度
max(s)
:序列中的最大值
min(s)
:序列中的最小值
range(start, end, step)
:生成start到end的数字,不包括end,步长为step
enumerate()
:将一个可遍历的数据对象组合为一个索引序列,同时列出数据和数据下标
sorted()
:排序,cpm比较函数,key用来比较的元素,reverse:排序规则(False升序,True降序)
all()
:都为True才返回True(空元组、空列表返回的是True)
any()
:有一个True就返回True
reverse()
:翻转,没有返回值,对列表元素本身进行翻转
zip()
:接收一个或多个可迭代对象,将对应的元素打包成一个元组,如果元素个数不一致,则以最短的长度为准,就算只有一个序列,也会把一个元素压缩成元组
字符串的不可变性
Python中的每一个对象都可以归为:可变的、不可变的
在核心类型中:数字、字符串、元组 等是不可变的,字典、列表、集合等是可变的
在原位置改变文本的数据,
- 一种方法是将它扩展为一个有独立字符构成的列表,然后将字符重新拼接起来。
- 另一种方法是使用 bytearray 类型(bytearray类型支持文本的原位置转换,但仅仅适用于字符编码至多8位宽(如ASCII)的文本,其他的所有字符串依然是不可变的)
字符串的方法学习
dir(S)
:列出了在调用者的作用域内,形式参数的默认值,返回了一个包含对象的所有属性的列表
help(S.方法名)
:查询具体方法的帮助信息
这里的S可以是实际的对象,也可以是 str 这样的类型
和字符串编码有关的内置函数
ascii(x)
:返回一个可打印的对象字符串表示方式,如果是非ascii字符则以 x,u等表示bin(x)
:将一个整数转换为二进制字符串ord(x)
:返回Unicode字符对应的整数(ascii、unicode)oct(x)
:整数转换为八进制字符串chr(x)
:返回数值对应的字符(ascii、unicode)
Unicode字符串
Python3.x的str类型可以处理Unicode字符串,并且使用一种独特的bytes字符串类型表示原始字节值
Unicode字符串能够分辨数字和字符,但在编码到文件或存储到内存时不一定要将文本字符映射成单字节,事实上,字节的概念并不适用于Unicode(一些Unicode码的一个字符大于一个字节,而且即使是7位的ascii字符,也不是存储为一个字符一字节的形式)
python3.x有一个严格的模型,禁止在没有显式转型的情况下,将普通字符串和字节串混合使用
- 存入文件:字节
- 读入内存:字符
文本在存入文件时被编码成字节,在读入内存时被解码成字符
列表
列表也是一个序列
列表是一个任意类型对象的位置相关的集合,没有固定的大小(尽管没有固定的大小,但仍然不允许引用不存在的元素)
列表是可
列表支持任意的嵌套
可以通过列表推导创建列表,如:[i for i in range(100)]
列表的格式:[x1, x2, x3, x4, x5]
字典
字典不是一种序列,而是一种映射
映射也是其他对象的集合,映射通过键(key)来存储对象
映射没有维护任何可靠的从左到右的顺序,只是简单地把键映射到相应的值上
对一个不存在的键赋值,会创建这个键
数值类型
在python中,数字并不是一种实际的对象类型,而是一些相似类型的分组
数值字面量
整数
整数直接写成十进制数字的串
Python2中的整数有两种类型,一般整数(32位)和长整数(无限精度),并且一个整数可以以 l 或 L 结尾,从而强制它转换为长整数。由于当整数的值超过为其分配的位数的时候会自动转换为长整数,所以一般不需要手动输入 L
Python3中整数变为了一种单独的类型,一般整数和长整数合二为一了,自动支持无限的精度(内存允许的情况下)
可以在整数字面量中间添加一些下划线,方便整数的阅读,而不影响这个字面量的值
a = 12_456_423
十六进制整数字面量:以 0x 或 0X 开头
八进制整数字面量:以 0o 或 0O 开头
二进制整数字面量:以 0b 或 0B 开头
浮点数
浮点数带一个小数点,也可以使用 e 或 E 进行科学计数法的表示
浮点数在标准CPython实现中是采用C语言的双精度来实现,因此其精度与用来构建Python解释器的C编译器所给定的双精度一样
复数
复数写成 实部 + 虚部,python中的虚部默认以 j 或 J 结尾
虚部可以独立于实部单独存在
混合基本数值类型的表达式 与 向上转换
如果一个表达式中有多种数值类型,Python会首先将被操作的对象转换成其中最复杂的操作数的类型,然后再对相同类型的操作数进行运算
整数比浮点数简单,浮点数比复数简单
这种混合类型的转换只适用于数值类型
一般来说,Python不会再其他的类型之间进行转换
非数值类型的比较
Python3不允许非数值类型的比较,会引发异常
Python2中,非数值类型也可以被比较,但是不会执行任何的转换(比较的是对象类型名称的字符串)
除法
Python3中的 /
是真除法,
python2和Python3中, //
是向下取整除法
Python2中的 /
是经典除法,会省去小数部分,对浮点数会保持余项(小数部分)
向下取整与截断
//
有一个别名,叫做截断除法,也叫做向下取整除法
在执行除法操作的时候,其实只是截断了正的结果,所以对于正数,截断除法和向下取整除法是相同的
对于负数,触发操作就是一个向下取整的结果
整数的精度
Python2中有一个专门用于长整数的类型,并且会自动把任何太长了的整数转变为这种长整数,而Python3中自动支持了无限精度的整数
由于Python需要为支持扩展精度而进行额外的工作,因此大精度的运算通常要比正常的整数运算更慢
当你要求精度的时候,你应该庆幸python内置了长整数的支持,而不是抱怨性能上的不足
进制字面量的转换
Python默认使用十进制显示整数数值,并且提供了内置函数将整数转换为其他进制的数字字符串
- oct:将十进制数转换为八进制字面量字符串(带前缀0o)
- hex:将十进制数转换为十六进制字面量字符串(带前缀0x)
- bin:将十进制数转换为二进制字面量字符串(带前缀0b)
按位操作整数
复数
内置函数 pow、abs
pow:用于计算幂
abs:用于计算绝对值,可以用于复数
字符串基础
字符串对象概述:"字符串"
字符串可以用来表示能够编码为文本或者字节的任何事物
字符串的概念
Unicode简介
在Python3.x中,有三种字符串类型:
- str 用于 Unicode 文本(包括 ASCII)
- bytes 用于二进制数据(包括已编码的文本)
- bytearray 是bytes的一个可修改的变体
文件在两种模式下工作:
- 文本:将内容表示为str类型并实现Unicode编码
- 二进制:以原始的bytes形式处理,且不做任何数据转换
在Python2.x中,unicode字符串表示Unicode文本,str字符串同时处理8位普通文本和二进制数据
bytearray从3.x向后移植,python2.6以后的2.x版本中可用
普通文件内容是由str直接表示的字节,但是codecs模块打开Unicode文件,处理编码,并将内容作为unicode对象表示
在Unicode世界中,“字节”没有任何意义
更为严格地讲,在Unicode语境下,字符串内容和长度都反应了码点(识别数字)值;无论在文件中编码或在内存中存储,Unicode中的单个字符不一定直接映射为单个字节。一一映射对于简单的7位ASCII文本可能有效,但即便是ASCII也依赖于外部编码类型和内部使用的存储方案,这取决于Python是如何为它们分配空间的
实际上,Python3.x形式上将str字符串定义为Unicode码点序列,而不是字节序列,以明确这一点。
为了安全起见,请在字符串中思考字符而不是字节
字符串字面量
一对单引号、一对双引号:可以表示普通的字符串
一对三引号(三个单引号或三个双引号):表示的字符串内部可以直接换行,即跨行表示。三引号字符串也叫 块字符串
两个字符串字面量直接放在一起,中间不加其他东西,会自动拼接为一个新的字符串
转义序列(略)
xhh
:十六进制hh的字符(两位)
ooo
:八进制ooo的字符(三位)
N{id}
:Unicode数据库ID
uhhhh
:16位十六进制值的Unicode字符
uhhhhhhhh
:32位十六进制值的Unicode字符
注:不管如何指定不可打印字符,Python都会以十六进制显示
字符串的结束?
Python中,如果使用了转义字符的空字符(