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 虚拟机将按照下面所述的方式执行:

  1. 设置 GIL
  2. 切换进一个线程去运行
  3. 执行操作之一(a.指定数量的字节码指令; b.线程主动调用time.sleep(0)让出控制权)
  4. 把线程设置回睡眠状态(切换出线程)
  5. 解锁 GIL
  6. 重复上述步骤

    使用线程

    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
2
3
4
5
6
7
8
9
fp = open('a.txt')     # 默认是以'r'模式打开,如果其它模式需要指定
fp = open('a.txt', 'w')# 以写的模式打开
# w: 写模式,如果文件已经存在,则会清空
# a:追加模式,如果文件已经存在,那么会在末尾添加数据
# w+:读写模式
fp.close()
使用with(一种上下文管理协议)可以避免忘记close()操作,例如
with open('a.txt', 'w') as data:
print("it's...", file=data)

从文件读取数据

1
2
3
fp.readline()    # 从文件获取一行数据
for each_line in fp: # 可迭代获取每一行数据
print(each_line)

文件指针

1
fp.seek(0)   # 回到文件的起始位置

检查文件是否存在

1
os.path.exists('filename')   # 返回布尔值

写入数据到文件

1
2
# 直接用print
print('string', file=fp)

读取 XML 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import xml.dom.minidom
#打开 XML 文档
xmlDoc = xml.dom.minidom.parse('test.xml')
root = xmlDoc.documentElement
# 获取“base”节点列表
baselist = root.getElementsByTagName('base')
# 用 while 循环所有 base 节点
i=0
while i<len (baselist)-1:
i=i+1
base=baselist[i]
baselang=base.getAttribute('loc')# 获取 base 节点中 loc 属性的值
print (baselang)
print (base.nodeName)
print (base.firstChild.data)# 获取节点的值

每一个结点都有它的 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 中读取文件, 基本和传统文件读取类似
    1
    2
    3
    4
    5
    import csv
    with open('data.csv', 'rb') as f:
    reader = csv.reader(f)
    for row in reader:
    print row
    向 csv 文件写入数据
    1
    2
    3
    4
    5
    6
    7
    8
    import 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 程序启动和运行起来需要以下五个主要步骤:
  1. 导入 tkinter 模块或 from Tkinter import *
  2. 创建一个顶层窗口对象,用于容纳整个 GUI 应用
  3. 在顶层窗口对象之上或者“其中”构建所有的 GUI 组件及其功能)
  4. 通过底层的应用代码将这些GUI组件连接起来
  5. 进入主事件循环

    窗口和控件

    在 GUI 编程中,顶层的根窗口对象包含组成 GUI 应用的所有小窗口对象;它们可能是文字标签、按钮、列表框等,这些独立的 GUI 组件称为控件
    所以当说创建一个顶层窗口时,只是表示需要一个地方来摆放所有的控件;控件可以独立存在,也可以作为容器存在;如果一个控件包含其他控件,就可以将其认为是那些控件的父控件
    相应地,如果一个控件被其他控件包含,则将其认为是那个控件的子控件,而父控件就是下一个直接包围它的容器控件。

    事件驱动处理

    控件有一些相关的行为,比如按下按钮、将文本写入文本框等;这些用户行为称为事件,而 GUI 对这类事件的响应称为回调
    事件可以包括按钮按下(及释放)、鼠标移动、敲击回车键等,一个 GUI 应用从开始到结束就是通过整套事件体系来驱动的,这种方式称为事件驱动处理

    布局管理器

    Tk 有 3 种布局管理器来帮助控件集进行定位
  • Placer

它的做法非常直接:提供控件的大小和摆放位置,然后管理器就会将其摆放好;问题是必须对所有控件进行这些操作,这样就会加重编程开发者的负担,因为这些操作本应该是自动完成的

  • Packer

它会把控件填充到正确的位置(即指定的父控件中),然后对于之后的每个控件,会去寻找剩余的空间进行填充;这个处理很像是旅行时往行李箱中填充行李的过程

  • Grid

基于网格坐标,使用 Grid 来指定 GUI 控件的放置;Grid 会在它们的网格位置上渲染 GUI 应用中的每个对象

GUI 示例

顶层窗口

1
2
import tkinter
top = tkinter.Tk()

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 通常省略,默认为 0
    1
    2
    3
    4
    5
    from 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 服务器
    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()
    SocketServer 模块以 socket 为基础而创建的高级套接字通信模块,支持客户端请求的线程和多线程处理
    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 集成工具包等