学习记录:Python
Python可应用于多平台包括 Linux 和 macOS,可以通过终端窗口输入 “python” 命令来查看本地是否已经安装Python 以及 Python 的安装版本。
基础
下载
Python 最新源码,二进制文档,新闻资讯等可以在 Python 的🔗 官网查看到;在🔗 此链接下载 Python 的文档,有 HTML、PDF 和 PostScript 等格式。
- https://github.com/pyenv/pyenv
- https://github.com/pyenv/pyenv-virtualenv
安装
Python 已经被移植在许多平台上(经过改动使它能够工作在不同平台上),需要下载适用于您使用平台的二进制代码,然后安装 Python。
如果您平台的二进制代码是不可用的,你需要使用 C 编译器手动编译源代码。
编译的源代码,功能上有更多的选择性, 为 Python 安装提供了更多的灵活性。运行
有三种方式可以运行 Python:交互式解释器:
以下为 Python 命令行参数:
选项 | 描述 |
---|---|
-d | 在解析时显示调试信息 |
-O | 生成优化代码 ( .pyo 文件 ) |
-S | 启动时不引入查找Python路径的位置 |
-V | 输出Python版本号 |
-c cmd | 执行 Python 脚本,并将运行结果作为 cmd 字符串。 |
file | 在给定的python文件执行python脚本。 |
命令行脚本
应用程序中通过引入解释器可以在命令行中执行 Python 脚本,如下所示:1
2
3$ python script.py #Unix/Linux
OR
C:>python script.py #Windows/DOS
集成开发环境(IDE:Integrated Development Environment)
IDLE
Python 自带编译器
PyCharm
PyCharm 是由 JetBrains 打造的一款 Python IDE,支持 macOS、 Windows、 Linux 系统。
PyCharm 功能 : 调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制……
PyCharm 下载地址 :https://www.jetbrains.com/pycharm/download/
Python 语言与 Perl,C 和 Java 等语言有许多相似之处,也存在一些差异。
交互式编程
交互式编程不需要创建脚本文件,是通过 Python 解释器的交互模式进来编写代码。
Linux 上只需要在命令行中输入 Python 命令即可启动交互式编程,提示窗口如下:
Window 上在安装 Python 时已经安装了交互式编程客户端,提示窗口如下:
在 python 提示符中输入以下文本信息,然后按 Enter 键查看运行效果:1
print ("Hello, Python!")
脚本式编程
通过脚本参数调用解释器开始执行脚本,直到脚本执行完毕;当脚本执行完成后,解释器不再有效。
所有 Python 文件将以 .py
为扩展名,将以下的源代码拷贝至 demo.py 文件中:1
print ("Hello, Python!")
如果已经设置了 Python 解释器 PATH 变量,直接使用以下命令运行程序:python demo.py
输出结果:Hello, Python!
GUI,Graphical User Interface(图形用户界面)编程主要使用的 GUI 工具包是 Python 默认的 GUI 库 Tk,通过 Python 的接口 Tkinter(“Tk interface”的缩写)可以访问 Tk
多线程编程
多线程编程对于具有如下特点的编程任务而言是非常理想的:本质上是异步的;需要多个并发活动;每个活动的处理顺序可能是不确定的,或者说是随机的、不可预测的。
这种编程任务可以被组织或划分成多个执行流,其中每个执行流都有一个指定要完成的任务。
- UserRequestThread
负责读取客户端输入,该输入可能来自 I/O 通道;程序将创建多个线程,每个客户端一个,客户端的请求将会被放入队列中
- RequestProcessor
该线程负责从队列中获取请求并进行处理,为第 3 个线程提供输出
- ReplyThread
负责向用户输出,将结果传回给用户(如果是网络应用),或者把数据写到本地文件系统或数据库中
进/线程
进程
计算机程序只是存储在磁盘上的可执行二进制(或其他类型)文件,只有把它们加载到内存中并被操作系统调用,才拥有其生命期
进程(有时称为重量级进程)则是一个执行中的程序,每个进程都拥有自己的地址空间、内存、数据栈以及其他用于跟踪执行的辅助数据
操作系统管理其上所有进程的执行,并为这些进程合理地分配时间;进程也可以通过派生(fork或spawn)新的进程来执行其他任务,不过因为每个新进程也都拥有自己的内存和数据栈等,所以只能采用进程间通信(IPC)的方式共享信息
线程
线程(有时候称为轻量级进程)与进程类似,不过它们是在同一个进程下执行的,并共享相同的上下文;可以将它们认为是在一个主进程或“主线程”中并行运行的一些“迷你进程”
线程包括开始、执行顺序和结束三部分;它有一个指令指针,用于记录当前运行的上下文;当其他线程运行时,它可以被抢占(中断)和临时挂起(也称为睡眠),这种做法叫做让步(yielding)
一个进程中的各个线程与主线程共享同一片数据空间,因此相比于独立的进程而言,线程间的信息技术和通信更加容易;线程一般是以并发方式执行的,正是由于这种并行和数据共享机制,使得多任务间的协作成为可能
Python 线程
Python 代码的执行是由 Python 虚拟机(又名解释器主循环)进行控制的,在设计时是这样考虑的:在主循环中同时只能有一个控制线程在执行,就像单核 CPU 系统中的多进程一样;内存中可以有许多程序,但是在任意给定时刻只能有一个程序在运行;同理,尽管 Python 解释器中可以运行多个线程,但是在任意给定时刻只有一个线程会被解释器执行
全局解释器锁
对 Python 虚拟机的访问是由全局解释器锁(GIL)控制的,用来保证同时只能有一个线程运行;在多线程环境中,Python 虚拟机将按照下面所述的方式执行:
- 设置 GIL
- 切换进一个线程去运行
- 执行操作之一(a.指定数量的字节码指令; b.线程主动调用
time.sleep(0)
让出控制权) - 把线程设置回睡眠状态(切换出线程)
- 解锁 GIL
- 重复上述步骤
使用线程
Python 提供了多个模块来支持多线程编程,包括 thread、threading 和 Queue 模块等
- 程序是可以使用 thread 和 threading 模块来创建与管理线程:thread 模块提供了基本的线程和锁定支持;而 threading 模块提供了更高级别、功能更全面的线程管理
- 使用 Queue 模块,用户可以创建一个队列数据结构,用于在多线程之间进行共享
PS.避免使用 thread 模块
- threading 模块更加先进,有更好的线程支持,并且 thread 模块中的一些属性会和 threading 模块有冲突
- 低级别的 thread 模块拥有的同步原语很少(只有一个),而 threading 模块则有很多
- thread 模块对于进程何时退出没有控制,当主线程结束时,所有其他线程也都强制结束,不会发出警告或者进行适当的清理,而 threading 模块能通过守护线程确保重要的子线程在进程退出前结束
thread 模块
threading 模块
thread 类
多线程实践
同步原语
锁示例
信号量示例
生产/消费者
Queue 模块
3.x 重命名为:queue线程的替代
subprocess 模块
是派生进程的主要替代方案,可以单纯地执行任务,或者通过标准文件(stdin、stdout、stderr)进行进程间通信multiprocessing 模块
2.6 版本起引入,允许为多核或多CPU 派生进程,其接口与 threading模块非常相似。该模块同样也包括在共享任务的进程间传输数据的多种方式concurrent.futures 模块
这是一个新的高级库,它只在“任务”级别进行操作,也就是说,不再需要过分关注同步和线程/进程的管理了;只需要指定一个给定了“worker”数量的线程/进程池,提交任务,然后整理结果。该模块自 Python 3.2 版本起引入,不过有一个 Python 2.6+ 可使用的移植版本,其网址为:http://code.google.com/p/pythonfutures
文件操作
文件的打开与关闭
1 | fp = open('a.txt') # 默认是以'r'模式打开,如果其它模式需要指定 |
从文件读取数据
1 | fp.readline() # 从文件获取一行数据 |
文件指针
1 | fp.seek(0) # 回到文件的起始位置 |
检查文件是否存在
1 | os.path.exists('filename') # 返回布尔值 |
写入数据到文件
1 | # 直接用print |
读取 XML 文件
1 | import xml.dom.minidom |
每一个结点都有它的 nodeName,nodeValue,nodeType 属性:nodeName 是结点名字;nodeValue 是结点的值,只对文本结点有效;nodeType 是结点的类型。
getElementsByTagName 方法获取指定名称的标签,getAttribute 方法可以获得元素的属性所对应的值,firstChild 属性返回被选节点的第一个子节点,.data 表示获取该节点人数据。
注意:
- 使用的是 Python 3.x;
- 如果循环控制语句条件设置不当,会造成内存溢出,报错:“list index out of range”;
- 文件名不要使用 xml.py,要不 import 会导入文件本身而出错:“No module named ‘xml.dom’; ‘xml’ is not a package”;
读取 CSV 文件
从 csv 中读取文件, 基本和传统文件读取类似向 csv 文件写入数据1
2
3
4
5import csv
with open('data.csv', 'rb') as f:
reader = csv.reader(f)
for row in reader:
print row1
2
3
4
5
6
7
8import csv
with open( 'data.csv', 'wb') as f:
writer = csv.writer(f)
writer.writerow(['name', 'address', 'age']) # 单行写入
data = [
( 'xiaoming ','china','10'),
( 'Lily', 'USA', '12')]
writer.writerows(data) # 多行写入GUI 编程
tkinter
tkinter 是 Python 的默认 GUI 库,它基于 Tk 工具包,该工具包最初是为工具命令语言(Tool Command Language,Tcl)设计的;Tk 普及后,被移植到很多其他的脚本语言中,包括 Perl(Perl/Tk)、Ruby(Ruby/Tk)和 Python(Tkinter)
让 GUI 程序启动和运行起来需要以下五个主要步骤:
- 导入 tkinter 模块或 from Tkinter import *
- 创建一个顶层窗口对象,用于容纳整个 GUI 应用
- 在顶层窗口对象之上或者“其中”构建所有的 GUI 组件及其功能)
- 通过底层的应用代码将这些GUI组件连接起来
- 进入主事件循环
窗口和控件
在 GUI 编程中,顶层的根窗口对象包含组成 GUI 应用的所有小窗口对象;它们可能是文字标签、按钮、列表框等,这些独立的 GUI 组件称为控件
所以当说创建一个顶层窗口时,只是表示需要一个地方来摆放所有的控件;控件可以独立存在,也可以作为容器存在;如果一个控件包含其他控件,就可以将其认为是那些控件的父控件
相应地,如果一个控件被其他控件包含,则将其认为是那个控件的子控件,而父控件就是下一个直接包围它的容器控件。事件驱动处理
控件有一些相关的行为,比如按下按钮、将文本写入文本框等;这些用户行为称为事件,而 GUI 对这类事件的响应称为回调
事件可以包括按钮按下(及释放)、鼠标移动、敲击回车键等,一个 GUI 应用从开始到结束就是通过整套事件体系来驱动的,这种方式称为事件驱动处理布局管理器
Tk 有 3 种布局管理器来帮助控件集进行定位
- Placer
它的做法非常直接:提供控件的大小和摆放位置,然后管理器就会将其摆放好;问题是必须对所有控件进行这些操作,这样就会加重编程开发者的负担,因为这些操作本应该是自动完成的
- Packer
它会把控件填充到正确的位置(即指定的父控件中),然后对于之后的每个控件,会去寻找剩余的空间进行填充;这个处理很像是旅行时往行李箱中填充行李的过程
- Grid
基于网格坐标,使用 Grid 来指定 GUI 控件的放置;Grid 会在它们的网格位置上渲染 GUI 应用中的每个对象
GUI 示例
顶层窗口
1 | import tkinter |
Tk 控件
控件 | 名称 | 描述 |
---|---|---|
Button | 按钮 | 类似标签,但提供额外的功能,例如鼠标掠过、按下、释放以及键盘操作/事件 |
Canvas | 画布 | 提供绘图功能(直线、椭圆、多边形、矩形),可以包含图形或位图 |
Checkbutton | 选择按钮 | 一组方框,可以选择其中的任意个(类似 HTML 中的 checkbox) |
Entry | 文本框 | 单行文字域,用来收集键盘输入(类似 HTML 中的 text) |
Frame | 框架 | 包含其他组件的纯容器 |
Label | 标签 | 用来显示文字或图片 |
LabelFrame | 标签框架 | 标签和框架的组合,拥有额外的标签属性 |
Listbox | 列表框 | 一个选项列表,用户可以从中选择 |
Menu | 菜单 | 点下菜单按钮后弹出的一个选项列表,用户可以从中选择 |
Menubutton | 菜单按钮 | 用来实现下拉式菜单 |
Message | 消息框 | 类似于标签,但可以显示多行文本 |
PanedWindow | 容器窗口 | 控制其他组件在其中摆放的容器控件 |
Radiobutton | 单选按钮 | 一组按钮,其中只有一个可被“按下” (类似 HTML 中的 radio) |
Scale | 进度条 | 线性“滑块”组件,可设定起始值和结束值,会显示当前位置的精确值 |
Scrollbar | 滚动条 | 对其支持的组件(文本域、画布、列表框、文本框)提供滚动功能 |
Spinbox | 旋转框 | 文本框和按钮的结合,允许对值进行调整 |
Text | 文本域 | 多行文字区域,可用来收集(或显示)用户输入的文字(类似 HTML 中的 textarea) |
Toplevel | 顶级 | 类似框架,但提供一个独立的窗口容器 |
其他 GUI
Tk 接口扩展(Tix)
Python MegaWidgets(PMW)
wxWidgets & wxPython
GTK+ & PyGTK
Tile & Ttk
网络编程
C/S 架构 & 套接字
C/S 架构的全称是 Client/Server,即客户端/服务器架构;它是一种网络体系架构,通常采取两层:服务器负责数据的管理,客户端负责完成与用户的交互任务
socket 即套接字,是计算机网络数据结构,任何类型的通信开始之前,网络应用必须创建套接字;最初是为同一主机上的应用程序创建,用于进程间通信(Inter Process Communication, IPC)。
类型:
- 基于文件
- 面向网路
家族:
- AF_UNIX / AF_LOCAL
- AF_INET
- AF_NETLINK
- AF_TIPC
套接字地址:主机-端口对(0-65535,小于 1024 为系统预留端口),https://www.iana.org/assignments/port-numbers
状态:
- 面向连接套接字:TCP/IP,SOCK_STREAM
- 无连接套接字:UDP/IP,SOCK_DGRAM
socket 模块
socket() 函数
函数语法:socket (socket_family, socket_type, protocol=0)
,protocol 通常省略,默认为 01
2
3
4
5from socket import *
#创建 TCP/IP 套接字
tcpSock = socket (AF_INET, SOCK_STREAM)
#创建 UDP/IP 套接字
udpSock = socket (AF_INET, SOCK_DGRAM)内置方法
| 用途 | 函数 | 描述 |
|———|————————-|————————————————-|
| 服务器端 | s.bind() | 绑定地址(主机名,端口号对)到套接字 |
| 服务器端 | s.listen() | 开始 TCP 监听 |
| 服务器端 | s.accept() | 被动接受 TCP 客户端链接,(阻塞式)等待链接的到来 |
| 客户端 | s.connect() | 主动初始化 TCP 服务器链接 |
| 客户端 | s.connect_ex() | connect() 扩展版本,出错时返回错误码,而不是抛出异常 |
| 公共用途 | s.recv() | 接受 TCP 数据 |
| 公共用途 | s.send() | 发送 TCP 数据 |
| 公共用途 | s.sendall() | 完整发送 TCP 数据 |
| 公共用途 | s.recvfrom() | 接受 UDP 数据 |
| 公共用途 | s.sendto() | 发送 UDP 数据 |
| 公共用途 | s.getpeername() | 链接到当前套接字的远程的地址(TCP 链接) |
| 公共用途 | s.getsockname() | 当前套接字的地址 |
| 公共用途 | s.getsockopt() | 返回当前套接字的参数 |
| 公共用途 | s.setsockopt() | 设置指定套接字的参数 |
| 公共用途 | s.close() | 关闭套接字 |
| 面向模块 | s.setblocking() | 设置套接字的阻塞与非阻塞模式 |
| 面向模块 | s.settimeout() | 设置阻塞套接字操做的超时时间 |
| 面向模块 | s.gettimeout() | 获得阻塞套接字操做的超时时间 |
| 面向文件 | s.fileno() | 套接字文件描述符 |
| 面向文件 | s.makefile() | 建立一个与该套接字关联的文件对 |伪代码实例
TCP 服务器
SocketServer 模块以 socket 为基础而创建的高级套接字通信模块,支持客户端请求的线程和多线程处理1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#创建 TCP/IP 服务器套接字
ss = socket ()
#套接字与地址绑定
ss.bind()
#监听连接
ss.listen()
#服务器无限循环
inf_loop:
#接受客户端连接
cs =ss.accept()
#通信循环
comm_loop:
#对话接收/发送
cs.recv()/cs.send()
#关闭客户端套接字
cs.close()
#关闭服务器套接字
ss.close()TCP 客户端
1
2
3
4
5
6
7
8
9
10#创建 TCP/IP 服务器套接字
cs = socket ()
#尝试连接服务器
cs.connect()
#通信循环
comm_loop:
#对话发送/接收
cs.send()/cs.recv()
#关闭客户端套接字
cs.close()UDP 服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14#创建 TCP/IP 服务器套接字
ss = socket ()
#套接字与地址绑定
ss.bind()
#监听连接
ss.listen()
#服务器无限循环
inf_loop:
#对话接收/发送
cs=ss.recvfrom()/ss.sendto()
#关闭客户端套接字
cs.close()
#关闭服务器套接字
ss.close()UDP 客户端
1
2
3
4
5
6
7
8#创建 TCP/IP 服务器套接字
cs = socket ()
#通信循环
comm_loop:
#对话发送/接收
cs.sendto()/cs.recvfrom()
#关闭客户端套接字
cs.close()socket 模块属性
SocketServer 模块
3.x 重命名为 socketserver,使编写一个 Socket 服务器通信变得更加简单,其实就是对 socket 的再封装模块类
| 类 | 描述 |
|——————————————————————-|———————————————————-|
| BaseServer | 包括服务器的核心功能与混合类的一些功能 |
| TCPServer/UDPServer | 基本的网络同步 TCP/UDP 服务器 |
| UnixStreamServer/UnixDatagramServer | 基本的文件同步 TCP/UDP 服务器 |
| ForkingMixIn/ThreadingMixIn | 实现了核心的进程/线程化功能,用于与服务器类进行混合,提供异步特性 |
| ForkingTCPServer/ForkingUDPServer | ForkingMixIn 和 TCPServer/UDPServer 组合 |
| ThreadingTCPServer/ThreadingUDPServer | Threading 和 TCPServer/UDPServer 组合 |
| BaseRequestHandler | 用于定制 Handler 类型 |
| StreamRequestHandler/DatagramRequestHandler | TCP/UDP 请求处理类的一个实现 |Twisted 框架
Twsited 是一个完整的事件驱动的网络框架,基于它能使用和开发完整的异步网络应用程序和协议;它不属于 Python 标准库,需要单独安装
它提供了大量的支持来建立完整的系统:网络协议、线程、安全性和身份认证、聊天/即时通信、数据库管理、关系数据库集成、Web/Internet、电子邮件、命令行参数、GUI 集成工具包等