目录
一、Python基础
Python的官方下载:Download Python | Python.org
注意:Python2和Python3有很多区别,建议装Python3的版本,Python 3.9.0后面的版本,要求Windows 7以上系统。
Pycharm windows版本下载地址:Download PyCharm: The Python IDE for data science and web development by JetBrains
下载社区版本(日常学习使用够用了),专业版是收费的哦(功能更强大)。
注意:Pycharm、Python和当前电脑系统都存在一个版本兼容问题,需要根据实际情况而定。
1、编码
Python2中默认编码为ASCII,Python3中默认编码为UTF-8,如需指定编码则在开头加入# -*- coding: UTF-8 -*- 进行指定。
2、标识符
由字母、数字、下划线组成,首字符必须为字母或下划线;在Python3中,可以用中文作为变量名,非ASCII标识符也是允许的。
3、关键字
Python的标准库提供了一个keyword模块,可以输出当前版本所有关键字,如:
>>> import keyword
>>> keyword.kwlist
4、注释
单行注释以#开头,多行注释以'''或"""包裹。
5、缩进
Python是使用缩进来表示代码块,同一代码块缩进相同,不需要使用{},如:
if True:
print ("Answer")
print ("True")
else:
print ("Answer")
6、语句
Python中通常时一行写完一条语句,无需分号,如果语句太长,可以使用反斜杠'\'连接,如:
total = item_one + \
item_two + \
item_three
在 [], {}, 或 () 中的多行语句,不需要使用反斜杠(\),如:
total = ['item_one', 'item_two', 'item_three',
'item_four', 'item_five']
Python也可以在同一行中使用多条语句,语句之间使用分号分割,如:
import sys; x = 'runoob'; sys.stdout.write(x + '\n')
在Python中,if __name__ == '__main__':
是一个常见的结构,用于检查当前模块是否作为主程序运行。这个结构对于理解Python的模块和脚本运行方式非常重要。
__name__
: 这是一个内置变量,它表示当前模块的名字。当一个Python文件(通常称为模块)被直接运行时,__name__
的值会被设置为 '__main__'
。但是,如果该文件被导入为另一个模块的一部分,__name__
的值就会被设置为该模块的名字。这个条件语句的意思是:“如果当前模块是作为主程序(而不是被其他模块导入)运行的,那么执行以下的代码块。”
使用这种结构的主要好处是,它允许一个Python文件既可以作为脚本直接运行,也可以作为模块被其他脚本导入,而无需修改其内容。当文件被导入时,if __name__ == '__main__':
下面的代码块不会被执行,这使得你可以在文件中定义函数、类等,而不用担心它们会在导入时被执行。
示例:
假设你有一个名为 my_module.py
的文件,内容如下:
def my_function():
print("This is a function in my_module.")
if __name__ == '__main__':
print("my_module is being run directly.")
my_function()
- 如果你直接运行
my_module.py
(例如,通过命令行输入python my_module.py
),输出将是:
my_module is being run directly.
This is a function in my_module.
-
如果你在另一个Python文件中导入
my_module
,例如:import my_module
那么不会有任何输出,因为 if __name__ == '__main__':
下的代码块不会被执行。但是,你仍然可以在那个文件中调用 my_module.my_function()
。
这种结构使得Python代码更加模块化和可重用。
7、字符串
单行字符串以单引号或双引号包裹,多行字符串以三引号包裹,如:
str1 = 'hello'
str2 = "world"
str3 = '''hello,
world'''
字符串中使用反斜杠'\'可用来转义,如'\n'可转义为换行,但使用r可以让反斜杠不发生转义,如:r"this is a line with \n" 此时\n会显示,并不会换行。
字符串可以用+连接,用*重复,如:
str1 = 'hello' + "world"
str2 = "world" * 3
字符串截取的语法格式:变量[头下标:尾下标:步长]
s = 'Python'
# 访问第一个字符P
print(s[0])
# 访问 yt
print(s[1:3])
# 访问 Pyt
print(s[:3])
# 访问 hon
print(s[3:])
#单个字符编码
s = 'A'
print(ord(s)) #输出结果:65
print(chr(65)) #输出结果:A
当我们需要输出的内容中含有变量时,比如:Hello xxx
,xxx
为变量,此时便需要一种格式化字符串的方式,Python 使用 %
格式化字符串,常用占位符如下表所示:
占位符 | 描述 |
---|---|
%s | 格式化字符串 |
%d | 格式化整数 |
%f | 格式化浮点数 |
print('Hello %s' % 'Python')
输出结果:Hello Python
我们也可以使用字符串的 format()
方法进行格式化,先看下示例:
print('{0} {1}'.format('Hello', 'Python'))
这种方式是用传入的参数依次替换字符串内的占位符{0}、{1} ...
8、导入
在python用import或者from...import来导入相应的模块;
如将整个模块导入,格式为:import somemodule
如导入模块中的某个函数,格式为:from somemodule import somefunction
如导入模块中的多个函数,格式为:from somemodule import firstfunc, secondfunc
如导入模块中的所有函数,格式为:from somemodule import *
9、函数
Python中使用def关键字来声明函数,格式如下:
def 函数名(参数):
函数体
return 返回值
当我们不确定参数个数时,可以使用不定长参数,在参数名前加*声明,格式如下:
def 函数名(*参数):
函数体
我们还可以使用lambda定义匿名函数,格式如下:
lambda 参数 : 表达式
# 空函数
def my_empty():
pass
# 无返回值
def my_print(name):
print('Hello', name)
# 有返回值
def my_sum(x, y):
s = x + y
print('s-->', s)
return s
# 不定长参数
def my_variable(*params):
for p in params:
print(p)
# 匿名函数
my_sub = lambda x, y: x - y
# 调用
my_empty()
my_print('Jhon')
result = my_sum(1, 2)
my_variable(1, 2, 3, 4, 5, 6)
print(my_sub(2, 1))
10、字典
Python中的数据结构字典(dict),它的内容以键值对的形式存在,dict拥有良好的查询速度,其中的值可以是任意Python对象。
创建字典方式如下:
d = {'name':'小明', 'age':'18'}
# 使用 dict 函数
# 方式一
l = [('name', '小明'), ('age', 18)]
d = dict(l)
# 方式二
d = dict(name='小明', age='18')
# 空字典
d = dict()
d = {}
访问字典方式如下:
>>> d = dict(name='小明', age='18')
>>> d['name']
'小明'
# 使用 get 方法
>>> d.get('name')
'小明'
修改字典方式如下:
>>> d = dict(name='小明', age='18')
>>> d['age'] = '20'
>>> d['age']
'20'
11、集合
集合(set)中的值不可重复,且无序。添加元素可以使用add或update方法,如果元素已经存在,则不进行操作。删除元素用remove方法。
创建集合方式如下:
s = {'a', 'b', 'c'}
# 使用 set 函数
s = set(['a', 'b', 'c'])
# 空集合
s = set()
>>> s = {'a', 'b', 'c'}
>>> s.add('d')
>>> s
{'a', 'd', 'c', 'b'}
>>> s.update('e')
>>> s
{'a', 'b', 'e', 'd', 'c'}
# 添加已经存在的元素 a
>>> s.add('a')
>>> s
{'a', 'b', 'e', 'd', 'c'}
#删除元素
>>> s = {'a', 'b', 'c'}
>>> s.remove('c')
>>> s
{'a', 'b'}
12、类
Python中类的定义使用class关键字,语法格式为:
class 类名:
属性
...
方法
...
#定义一个Cat类
class Cat:
# 属性
color = 'black'
# 构造方法
def __init__(self, name):
self.name = name
# 自定义方法
def eat(self, food):
self.food = food
print(self.name, '正在吃'+food)
构造方法__init__()会在类实例化时自动调用,无论构造方法还是其他方法都需要将self作为第一个参数,它代表类的实例。
类中定义的属性和方法默认都是公开的,如果不想外部访问和调用,则需要定义成私有属性和方法,声明时在属性名和方法名前加两条下划线即可,如下:
class Cat:
__cid = '1'
def __run(self):
pass
创建对象也称类的实例化,创建对象后可以访问属性和方法调用了,如下:
# 创建对象
c = Cat('Tom')
# 访问属性
print('name-->', c.name)
print('color-->', c.color)
# 调用方法
c.eat('鱼')
Python支持类的继承,而且支持多继承,语法格式为:
class 基类(子类1, 子类2 ...):
...
示例代码:
# 波斯猫类
class PersianCat(Cat):
def __init__(self, name):
self.name = name
def eat(self, food):
print(self.name, '正在吃'+food)
#加菲猫类
class GarfieldCat(Cat):
def __init__(self, name):
self.name = name
def run(self, speed):
print(self.name, '正在以'+speed+'的速度奔跑')
# 单继承
class SingleCat(PersianCat):
pass
# 多继承
class MultiCat(PersianCat, GarfieldCat):
pass
#调用
sc = SingleCat('波斯猫1号')
sc.eat('鱼')
mc = MultiCat('波斯加菲猫1号')
mc.eat('鱼')
mc.run('50迈')
如果继承的父类方法不能满足我们的要求,这时子类可以重写父类方法,如下:
class SingleCat(PersianCat):
def eat(self, food ):
print(self.name, '正在吃'+food, '十分钟后', self.name+'吃饱了')
sc = SingleCat('波斯猫1号')
sc.eat('鱼')
13、文件基本操作
利用Python中内置的一些函数实现文件的基本操作:创建、打开、读、写、关闭。话不多说,直接上代码:
# 打开或创建文件
f = open('test.txt', 'w', encoding='utf-8')
# 写入一行
f.write('Tom\n')
# 写入多行
f.writelines(['Hello\n', 'Python'])
# 文件对象位置
print(f.tell())
# 移动到文件的第四个字节
f.seek(3)
# 读取一行
f.readline()
# 读取指定字节数
f.read(6)
# 读取所有行
f.readlines()
# 关闭文件
f.close()
创建或打开文件:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
# file:表示将要打开的文件的路径,也可以是要被封装的整数类型文件描述符。
# mode:用于指定打开文件的模式。
r 读取(默认)
w 写入,并先截断文件
x 排它性创建,如果文件已存在则失败
a 写入,如果文件存在则在末尾追加
b 二进制模式
t 文本模式(默认)
+ 更新磁盘文件(读取并写入)
# buffering:是一个可选的整数,用于设置缓冲策略。
# encoding:用于解码或编码文件的编码的名称。
# errors:用于指定如何处理编码和解码错误(不能在二进制模式下使用)。
# newline:区分换行符。
# closefd:如果 closefd 为 False 并且给出了文件描述符而不是文件名,那么当文件关闭时,底层文件描述符将保持打开状态;如果给出文件名,closefd 为 True (默认值),否则将引发错误。
# opener:可以通过传递可调用的 opener 来使用自定义开启器。
上面我们使用了 close() 函数进行关闭操作,如果忘记了关闭,可能会对程序造成一些隐患,为了避免这个问题的出现,可以使用 with as 语句,通过这种方式,程序执行完成后会自动关闭已经打开的文件。如:
with open('test.txt', 'w', encoding='utf-8') as wf:
wf.write('Tom\n')
wf.writelines(['Hello\n', 'Python'])
在Python中,with as语句用于确保一段代码执行完毕时,可以正确地清理所使用的资源。这通常用于管理文件、网络连接、数据库连接、线程锁等资源的生命周期。使用with语句可以确保资源在使用完毕后被正确关闭或释放,即使在代码块执行过程中发生异常也是如此。
with expression [as variable]:
with-block
其中,expression
必须返回一个上下文管理对象,该对象必须实现__enter__()
和__exit__()
两个方法。当with
语句开始时,__enter__()
方法被调用,其返回值(如果有的话)会被赋值给as
关键字后面的变量。当with
语句块执行完毕(无论正常结束还是由于异常退出)时,__exit__()
方法被调用。
二、Python进阶
1、多线程
Python解释器的作用是将.py文件中的代码翻译后交给机器去执行,常见解释器有:CPython、Jython、IronPython、IPython、PyPy,而CPython是官方解释器,通过GIL(全局解释器锁)机制来确保同一时间只有一个线程来执行Python代码,解决并发访问的线程安全问题,但却牺牲了多处理器上的并行性,所有CPython解释器上的多线程并不是真正意义上的多线程。
Python(CPython)提供了_thread和_threading两个线程模块,_threading是对_thread进行了封装,这里只介绍_threading模块。
守护线程:当一个线程被设置为守护线程时,程序会在所有线程都为守护线程时退出,资源可能不被正确释放。
非守护线程:默认创建的线程为非守护线程,程序退出时会等待所有非守护线程运行完毕。
常用方法如下:
threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
创建线程对象,参数说明如下所示。
-
group:通常默认即可,作为日后扩展 ThreadGroup 类实现而保留。
-
target:用于 run() 方法调用的可调用对象,默认为 None。
-
name:线程名称,默认是 Thread-N 格式构成的唯一名称,其中 N 是十进制数。
-
args:用于调用目标函数的参数元组,默认为 ()。
-
kwargs:用于调用目标函数的关键字参数字典,默认为 {}。
-
daemon:设置线程是否为守护模式,默认为 None。
start()
启动线程。
run()
线程执行具体功能的方法。
join(timeout=None)
当 timeout 为 None 时,会等待至线程结束;当 timeout 不为 None 时,会等待至 timeout 时间结束,单位为秒。
is_alive()
判断线程是否存活。
getName()
返回线程名。
setName()
设置线程名。
isDaemon()
判断线程是否为守护线程。
setDaemon()
设置线程是否为守护线程。
import threading
import time
def target(sleep):
time.sleep(sleep)
print('当前线程为:', threading.current_thread().name,' ', 'sleep:', sleep)
if __name__ == '__main__':
t1 = threading.Thread(name='t1', target=target, args=(1,))
t2 = threading.Thread(name='t2', target=target, args=(2,))
t1.start()
t2.start()
print('主线程结束')
#继承 threading.Thread
class MyThread(threading.Thread):
def __init__(self, sleep, name):
super().__init__()
self.sleep = sleep
self.name = name
def run(self):
time.sleep(self.sleep)
print('name:' + self.name)
if __name__ == '__main__':
t1 = MyThread(1, 't1')
t2 = MyThread(1, 't2')
t1.start()
t2.start()
互斥锁:
多线程访问共享资源时会存在线程安全问题,此时就需要互斥锁来控制每一个线程访问顺序。
threading.Lock
实现原始锁对象的类,一旦一个线程获得一个锁,会阻塞随后尝试获得锁的线程,直到它被释放,通常称其为互斥锁,它是由 _thread 模块直接扩展实现的。它具有如下方法:
-
acquire(blocking=True, timeout=-1):可以阻塞或非阻塞地获得锁,参数 blocking 用来设置是否阻塞,timeout 用来设置阻塞时间,当 blocking 为 False 时 timeout 将被忽略。
-
release():释放锁。
-
locked():判断是否获得了锁,如果获得了锁则返回 True。
threading.RLock
可重入锁(也称递归锁)类,一旦线程获得了重入锁,同一个线程再次获取它将不阻塞,重入锁必须由获取它的线程释放。它具有如下方法:
-
acquire(blocking=True, timeout=-1):解释同上。
-
release():解释同上。
我们对上述代码进行加锁操作,如下所示:
import threading
# 创建锁
lock = threading.Lock()
a = 5
def oper(b):
# 获取锁
lock.acquire()
global a
a = a - b
a = a + b
# 释放锁
lock.release()
def target(b):
for i in range(100000):
oper(b)
if __name__ == '__main__':
m = 5
while m > 0:
t1 = threading.Thread(target=target, args=(1,))
t2 = threading.Thread(target=target, args=(2,))
t1.start()
t2.start()
t1.join()
t2.join()
print(a)
m = m - 1
条件对象:
条件对象总是与某种类型的锁对象相关联,锁对象可以通过传入获得,或者在缺省的情况下自动创建。
threading.Condition(lock=None)
实现条件对象的类。它具有如下方法:
-
acquire(*args):请求底层锁。
-
release():释放底层锁。
-
wait(timeout=None):等待直到被通知或发生超时。
-
wait_for(predicate, timeout=None):等待直到条件计算为 True,predicate 是一个可调用对象且它的返回值可被解释为一个布尔值。
-
notify(n=1):默认唤醒一个等待该条件的线程。
-
notify_all():唤醒所有正在等待该条件的线程。
使用条件对象的典型场景是将锁用于同步某些共享状态的权限,那些关注某些特定状态改变的线程重复调用 wait() 方法,直到所期望的改变发生;对于修改状态的线程,它们将当前状态改变为可能是等待者所期待的新状态后,调用 notify() 方法或者 notify_all() 方法。
import time
import threading
# 创建条件对象
c = threading.Condition()
privilege = 0
def getPri():
global privilege
c.acquire()
c.wait()
print(privilege)
c.release()
def updPri():
time.sleep(5)
c.acquire()
global privilege
privilege = 1
c.notify()
c.release()
if __name__ == '__main__':
t1 = threading.Thread(target=getPri)
t2 = threading.Thread(target=updPri)
t1.start()
t2.start()
信号量对象:
和锁机制一样,信号量机制也是一种实现线程同步的机制,不过它比锁多了一个计数器,这个计数器主要用来计算当前剩余的锁的数量。
threading.Semaphore(value=1)
信号量实现类,可选参数 value 赋予内部计数器初始值,默认值为 1 。它具有如下方法:
-
acquire(blocking=True, timeout=None):获取一个信号量,参数 blocking 用来设置是否阻塞,timeout 用来设置阻塞时间。
-
release():释放一个信号量,将内部计数器的值增加1。
import threading
# 创建信号量对象
s = threading.Semaphore(10)
a = 5
def oper(b):
# 获取信号量
s.acquire()
global a
a = a - b
a = a + b
# 释放信号量
s.release()
def target(b):
for i in range(100000):
oper(b)
if __name__ == '__main__':
m = 5
while m > 0:
t1 = threading.Thread(target=target, args=(1,))
t2 = threading.Thread(target=target, args=(2,))
t1.start()
t2.start()
t1.join()
t2.join()
print(a)
m = m - 1
事件对象:
一个线程发出事件信号,其他线程等待该信号,这是最简单的线程之间通信机制之一。
threading.Event
实现事件对象的类。它有如下方法:
-
is_set():当内部标志为 True 时返回 True。
-
set():将内部标志设置为 True。
-
clear():将内部标志设置为 False。
-
wait(timeout=None):阻塞线程直到内部变量为 True。
import time
import threading
# 创建事件对象
event = threading.Event()
def dis_class():
time.sleep(5)
event.wait()
print('同学们下课了')
def bell():
time.sleep(3)
print('下课铃声响了')
event.set()
if __name__ == '__main__':
t1 = threading.Thread(target=bell)
t2 = threading.Thread(target=dis_class)
t1.start()
t2.start()
t1.join()
t2.join()
2、多进程
进程:通常一个运行着的应用程序就是一个进程,比如:我启动了一个音乐播放器,现在它就是一个进程。线程:线程是进程的最小执行单元,比如:我在刚启动的音乐播放器上选了一首歌曲进行播放,这就是一个线程。
在多线程一文中,我们说了因为 GIL 的原因,CPython 解释器下的多线程牺牲了并行性,为此 Python 提供了多进程模块 multiprocessing,该模块同时提供了本地和远程并发,使用子进程代替线程,可以有效的避免 GIL 带来的影响,能够充分发挥机器上的多核优势,可以实现真正的并行效果,并且它与threading模块的 API 基本类似,使用起来也比较方便。
Process类:
multiprocessing模块通过创建一个Process对象,然后调用它的start()方法来生成进程,
multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
-
group:仅用于兼容 threading.Thread,应该始终是 None。
-
target:由 run() 方法调用的可调用对象。
-
name:进程名。
-
args:目标调用的参数元组。
-
kwargs:目标调用的关键字参数字典。
-
daemon:设置进程是否为守护进程,如果是默认值 None,则该标志将从创建的进程继承。
multiprocessing.Process 对象具有如下方法和属性:
-
run():进程具体执行的方法。
-
start():启动进程。
-
join([timeout]):如果可选参数 timeout 是默认值 None,则将阻塞至调用 join() 方法的进程终止;如果 timeout 是一个正数,则最多会阻塞 timeout 秒。
-
name:进程的名称。
-
is_alive():返回进程是否还活着。
-
daemon:进程的守护标志,是一个布尔值。
-
pid:返回进程 ID。
-
exitcode:子进程的退出代码。
-
authkey:进程的身份验证密钥。
-
sentinel:系统对象的数字句柄,当进程结束时将变为 ready。
-
terminate():终止进程。
-
kill():与 terminate() 相同,但在 Unix 上使用 SIGKILL 信号。
-
close():关闭 Process 对象,释放与之关联的所有资源。
看一个使用多进程的示例:
from multiprocessing import Process
import time, os
def target():
time.sleep(2)
print ('子进程ID:', os.getpid())
if __name__=='__main__':
print ('主进程ID:', os.getpid())
ps = []
for i in range(10):
p = Process(target=target)
p.start()
ps.append(p)
for p in ps:
p.join()
进程池:
当进程数量比较多时,我们可以利用进程池方便、高效的对进程进行使用和管理。
multiprocessing.pool.Pool([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])
-
processes:工作进程数目,如果 processes 为 None,则使用 os.cpu_count() 返回的值。
-
initializer:如果 initializer 不为 None,则每个工作进程将会在启动时调用 initializer(*initargs)。
-
maxtasksperchild:一个工作进程在它退出或被一个新的工作进程代替之前能完成的任务数量,为了释放未使用的资源。
-
context:用于指定启动的工作进程的上下文。
有如下两种方式向进程池提交任务:
-
apply(func[, args[, kwds]]):阻塞方式。
-
apply_async(func[, args[, kwds[, callback[, error_callback]]]]):非阻塞方式。
import multiprocessing, time
def target(p):
print('t')
time.sleep(2)
print(p)
if __name__ == "__main__":
pool = multiprocessing.Pool(processes = 5)
for i in range(3):
p = 'p%d'%(i)
# 阻塞式
pool.apply(target, (p, ))
# 非阻塞式
# pool.apply_async(target, (p, ))
pool.close()
pool.join()
3、进程间通信
管道:
共享队列:
互斥锁和信号量:
共享内存:
4、Excel 基本操作
Python 中常用 Excel 操作库如下:
-
xlrd:从 Excel 中读取数据,支持 xls、xlsx。
-
xlwt:向 Excel 中写入数据,支持 xls。
-
xlutils:提供了一些 Excel 的实用操作,比如复制、拆分、过滤等,通常与 xlrd、xlwt 一起使用。
-
XlsxWriter:向 Excel 中写入数据,支持 xlsx。
-
openpyxl :用于读写 Excel,支持 xlsx。
使用xlwt库,
pip install xlwt 命令安装。示例如下:
import xlwt
# 创建工作簿
wb = xlwt.Workbook()
# 添加表单
sh = wb.add_sheet('test')
# 创建样式1,字体加粗
font = xlwt.Font()
font.bold = True
style1 = xlwt.XFStyle()
style1.font = font
# 创建样式2,左对齐
alm = xlwt.Alignment()
alm.horz = 0x01
style2 = xlwt.XFStyle()
style2.alignment = alm
# 向表中写入数据,参数1:行,参数2:列,参数3:内容,参数4:样式
sh.write(0, 1, '姓名', style1)
sh.write(0, 2, '年龄', style1)
sh.write(1, 1, '张三')
sh.write(1, 2, 50, style2)
sh.write(2, 1, '李四')
sh.write(2, 2, 30, style2)
sh.write(3, 1, '王五')
sh.write(3, 2, 40, style2)
sh.write(4, 1, '赵六')
sh.write(4, 2, 60, style2)
sh.write(5, 0, '平均年龄', style1)
# 保存
wb.save('test.xls')
输出结果:
使用XlsxWriter库,
pip install XlsxWriter 命令安装。示例如下:
import xlsxwriter
# 创建工作簿
workbook = xlsxwriter.Workbook('test.xlsx')
# 添加表单
sh = workbook.add_worksheet('test')
# 创建样式1,字体加粗
fmt1 = workbook.add_format()
fmt1.set_bold(True)
# 创建样式2,左对齐
fmt2 = workbook.add_format()
fmt2.set_align('left')
# 数据
data = [['', '姓名', '年龄'],
['', '张三', 50],
['', '李四', 30],
['', '王五', 40],
['', '赵六', 60],
['平均年龄', '', ]]
sh.write_row('A1', data[0], fmt1)
sh.write_row('A2', data[1], fmt2)
sh.write_row('A3', data[2], fmt2)
sh.write_row('A4', data[3], fmt2)
sh.write_row('A5', data[4], fmt2)
sh.write_row('A6', data[5], fmt1)
# 关闭
workbook.close()
输出结果:
使用xlrd库,
pip install xlrd 命令安装。示例如下:
import xlrd
# 打开文件
wb = xlrd.open_workbook('test.xlsx')
print( 'sheet名称:', wb.sheet_names())
print( 'sheet数量:', wb.nsheets)
# 根据 sheet 索引获取 sheet
sh = wb.sheet_by_index(0)
# 根据 sheet 名称获取 sheet
# sh = wb.sheet_by_name('test')
print( u'sheet %s 有 %d 行' % (sh.name, sh.nrows))
print( u'sheet %s 有 %d 列' % (sh.name, sh.ncols))
print('第二行内容:', sh.row_values(1))
print('第三列内容:', sh.col_values(2))
print('第二行第三列的值为:', sh.cell_value(1, 2))
print('第二行第三列值的类型为:', type(sh.cell_value(1, 2)))
使用xlutils库,
pip install xlutils 命令安装。示例如下:
import xlrd, xlwt
from xlutils import copy
def avg(list):
sumv = 0
for i in range(len(list)):
sumv += list[i]
return int(sumv / len(list))
# 打开文件,formatting_info为True表示保留原格式
wb = xlrd.open_workbook('test.xls', formatting_info=True)
# 获取第一张表
sh = wb.sheet_by_index(0)
# 读取第二列所有值
age_list = sh.col_values(2)
age_list = age_list[1:len(age_list)-1]
# 计算平均值
avg_age = avg(age_list)
# 复制文件
wbc = copy(wb)
# 获取第一张表
sh = wbc.get_sheet(0)
# 设置左对齐
alm = xlwt.Alignment()
alm.horz = 0x01
style = xlwt.XFStyle()
style.alignment = alm
# 写入平均值
sh.write(5, 2, avg_age, style)
# 保存同一个文件
wbc.save('test.xls')
输出结果:
5、Word 基本操作
Python 提供了 python-docx 库,该库就是为 Word 文档量身定制的,安装使用pip install python-docx 命令即可。
写入word,示例如下:
from docx import Document
from docx.shared import Inches
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.shared import Cm, Pt
# 创建文档
document = Document()
style = document.styles['Normal']
# 标题
t0 = document.add_heading('标题0', 0)
# 居中
t0.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
document.add_heading('标题1', 1)
# 首行缩进两个字符
paragraph_format = style.paragraph_format
paragraph_format.first_line_indent = Cm(0.74)
# 段落
p1 = document.add_paragraph('你们平时')
# 字体加粗
p1.add_run('Word文档').bold = True
# 斜体
p1.add_run('用的多吗?').italic = True
# 列表
document.add_paragraph('A:我们用的多', style='List Bullet')
document.add_paragraph('B:我们用的少', style='List Bullet')
document.add_paragraph('C:我们用的不多不少', style='List Bullet')
document.add_heading('标题2', 2)
# 段落
p2 = document.add_paragraph('我平时基本都是手动操作Word文档,现在打算利用Python来操作它,'
'你们平时是手动操作Word文档?如果是的话,')
run = p2.add_run('一起来了解下如何通过Python来操作吧!')
# 设置字体大小
run.font.size = Pt(12)
# 表格
table = document.add_table(rows=3, cols=2, style='Table Grid')
# 表头
hc = table.rows[0].cells
hc[0].text = '姓名'
hc[1].text = '年龄'
# 表体
bc1 = table.rows[1].cells
bc1[0].text = '张三'
bc1[1].text = '22'
bc2 = table.rows[2].cells
bc2[0].text = '李四'
bc2[1].text = '33'
# 分页
# document.add_page_break()
# 图片
document.add_picture('pic.jpg', width=Inches(1))
# 保存
document.save('test.docx')
输出结果:
读取word,示例如下:
from docx import Document
# 打开文档
document = Document('test.docx')
# 读取标题、段落、列表内容
ps = [ paragraph.text for paragraph in document.paragraphs]
for p in ps:
print(p)
# 读取表格内容
ts = [table for table in document.tables]
for t in ts:
for row in t.rows:
for cell in row.cells:
print(cell.text, end=' ')
print()
6、XML 基本操作
通常 Python 可以通过如下三种方式来解析 XML:
-
DOM:该方式将整个 XML 读入内存,在内存中解析成一个树,通过对树的操作来操作 XML,该方式占用内存较大,解析速度较慢。
-
SAX:该方式将逐行扫描 XML 文档,边扫描边解析,占用内存较小,速度较快,缺点是不能像 DOM 方式那样长期留驻在内存,数据不是长久的,事件过后,若没保存数据,数据会丢失。
-
ElementTree:该方式几乎兼具了 DOM 方式与 SAX 方式的优点,占用内存较小、速度较快、使用也较为简单。
写入xml,示例如下:
from xml.etree import ElementTree as et
import xml.dom.minidom as minidom
# 创建根节点
root = et.Element('school')
names = ['张三', '李四']
genders = ['男', '女']
ages = ['20', '18']
# 添加子节点
student1 = et.SubElement(root, 'student')
student2 = et.SubElement(root, 'student')
et.SubElement(student1, 'name').text = names[0]
et.SubElement(student1, 'gender').text = genders[0]
et.SubElement(student1, 'age').text = ages[0]
et.SubElement(student2, 'name').text = names[1]
et.SubElement(student2, 'gender').text = genders[1]
et.SubElement(student2, 'age').text = ages[1]
# 将根目录转化为树行结构
tree = et.ElementTree(root)
rough_str = et.tostring(root, 'utf-8')
# 格式化
reparsed = minidom.parseString(rough_str)
new_str = reparsed.toprettyxml(indent='\t')
f = open('test.xml', 'w', encoding='utf-8')
# 保存
f.write(new_str)
f.close()
输出结果:
通过DOM方式解析XML,示例如下:
from xml.dom.minidom import parse
# 读取文件
dom = parse('test.xml')
# 获取文档元素对象
elem = dom.documentElement
# 获取 student
stus = elem.getElementsByTagName('student')
for stu in stus:
# 获取标签中内容
name = stu.getElementsByTagName('name')[0].childNodes[0].nodeValue
gender = stu.getElementsByTagName('gender')[0].childNodes[0].nodeValue
age = stu.getElementsByTagName('age')[0].childNodes[0].nodeValue
print('name:', name, ', gender:', gender, ', age:', age)
输出结果:
name: 张三 , gender: 男 , age: 20
name: 李四 , gender: 女 , age: 18
通过 SAX 方式进行解析XML,示例如下:
import xml.sax
class StudentHandler(xml.sax.ContentHandler):
def __init__(self):
self.name = ''
self.age = ''
self.gender = ''
# 元素开始调用
def startElement(self, tag, attributes):
self.CurrentData = tag
# 元素结束调用
def endElement(self, tag):
if self.CurrentData == 'name':
print('name:', self.name)
elif self.CurrentData == 'gender':
print('gender:', self.gender)
elif self.CurrentData == 'age':
print('age:', self.age)
self.CurrentData = ''
# 读取字符时调用
def characters(self, content):
if self.CurrentData == 'name':
self.name = content
elif self.CurrentData == 'gender':
self.gender = content
elif self.CurrentData == 'age':
self.age = content
if (__name__ == "__main__"):
# 创建 XMLReader
parser = xml.sax.make_parser()
# 关闭命名空间
parser.setFeature(xml.sax.handler.feature_namespaces, 0)
# 重写 ContextHandler
Handler = StudentHandler()
parser.setContentHandler(Handler)
parser.parse('test.xml')
输出结果:
name: 张三
gender: 男
age: 20
name: 李四
gender: 女
age: 18
通过 ElementTree 方式进行解析XML,示例如下:
import xml.etree.ElementTree as et
tree = et.parse('test.xml')
# 根节点
root = tree.getroot()
for stu in root:
print('name:', stu[0].text, ', gender:', stu[1].text, ', age:', stu[2].text)
输出结果:
name: 张三 , gender: 男 , age: 20
name: 李四 , gender: 女 , age: 18
7、JSON 基本操作
Python 标准库的 json 模块可以用来处理 JSON 格式数据的基本操作。json 模块主要提供了 dump、dumps、load、loads 方法对 JSON 数据进行编解码。
Python 类型也可转成 JSON 格式的字符串,它们之间有对应关系如下所示:
Python | JSON |
---|---|
dict | object |
list, tuple | array |
str | string |
iint, float, int 和 float 派生的枚举 | number |
True | true |
False | false |
None | null |
import json
# 字典
d = {'id':'001', 'name':'张三', 'age':'20'}
# 转json格式字符串
j = json.dumps(d, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ': '))
# 输出
print(j)
# 写入文件
with open('test.json', 'w', encoding='utf-8') as f:
f.write(j)
输出结果:
{
"age": "20",
"id": "001",
"name": "张三"
}
如果我们需要将数据写到文件里的时候,dump 方法会比 dumps 方法方便一点,看一下示例:
import json
d = {'id':'001', 'name':'张三', 'age':'20'}
with open('test.json', 'w', encoding='utf-8') as f:
json.dump(d, f, indent=4, ensure_ascii=False)
json 模块的 loads 方法可以将 JSON 格式数据转为 Python 对象,看个示例:
import json
j = '{"id":"001", "name":"张三", "age":"20"}'
d = json.loads(j)
print(d)
输出结果:
{'id': '001', 'name': '张三', 'age': '20'}
两者之间转换的对应关系如下所示:
JSON | Python |
---|---|
object | dict |
array | list |
string | str |
number (int) | int |
number (real) | float |
true | True |
false | False |
null | None |
我们再来读取一下之前生成的 test.json 中数据并将其转为 Python 对象,如下所示:
import json
with open('test.json', encoding='utf-8') as f:
data = f.read()
print(json.loads(data))
执行结果:
{'id': '001', 'name': '张三', 'age': '20'}
json 模块的 load 方法将文件类对象转为 Python 对象,看个示例:
import json
with open('test.json', encoding='utf-8') as f:
print(json.load(f))
执行结果:
{'id': '001', 'name': '张三', 'age': '20'}
我们可以看出 load 方法传的参数是文件对象,而 loads 方法参数传的是字符串。
三、库
1、Requests库
Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用。警告:非专业使用其他 HTTP 库会导致危险的副作用,包括:安全缺陷症、冗余代码症、重新发明轮子症、啃文档症、抑郁、头疼、甚至死亡。
安装使用终端命令 pip install requests
。
导入 Requests 模块:import requests
发送请求:
常见 HTTP 请求类型 head、get、post、put、delete 的示例:
r = requests.head('http://xxx.xxx')
r = requests.get('http://xxx.xxx/get')
r = requests.post('http://xxx.xxx/post', data = {'key':'value'})
r = requests.put('http://xxx.xxx/put', data = {'key':'value'})
r = requests.delete('http://xxx.xxx/delete')
通常我们会设置请求的超时时间,Requests 使用 timeout
参数来设置,单位是秒,示例如下:
r = requests.head('http://xxx.xxx/get', timeout=1)
head 请求与 get 请求类似,但是服务器在响应中只返回 HTTP 头部信息,而不返回实际的数据内容。这使得 head 请求在检查资源的存在性、获取资源的元信息(如内容类型、长度、修改时间等)时非常有用,因为它避免了传输整个资源内容所带来的额外开销。
参数传递:
在使用 get 方式发送请求时,我们会将键值对形式参数放在 URL 中问号(?)的后面,如:http://xxx.xxx/get?key=val
,Requests 通过 params 关键字,以一个字符串字典来提供这些参数。比如要传 key1=val1
和 key2=val2
到 http://xxx.xxx/get
,示例如下:
pms= {'key1': 'val1', 'key2': 'val2'}
r = requests.get("http://xxx.xxx/get", params=pms)
Requests 还允许将一个列表作为值传入:
pms= {'key1': 'val1', 'key2': ['val2', 'val3']}
注
:字典里值为 None 的键都不会被添加到 URL 的查询字符串里。
响应内容:
我们来获取一下服务器的响应内容,这里地址 https://api.github.com
为例:
import requests
r = requests.get('https://api.github.com')
print(r.text)
# 输出结果
# {"current_user_url":"https://api.github.com/user","current_user...
当访问 r.text 之时,Requests 会使用其推测的文本编码,我们可以使用r.encoding查看其编码,也可以修改编码,如:r.encoding = 'GBK'
,当改变了编码,再次访问 r.text 时,Request 都将会使用 r.encoding 的新值。
1)二进制响应内容 比如当我们要获取一张图片的数据,会以二进制的方式获取响应数据,示例如下:
from PIL import Image
from io import BytesIO
i = Image.open(BytesIO(r.content))
2)JSON响应内容 Requests 中已经内置了 JSON 解码器,因此我们可以很容易的对 JSON 数据进行解析,示例如下:
import requests
r = requests.get('https://api.github.com')
r.json()
注
:成功调用 r.json() 并不一定响应成功,有的服务器会在失败的响应中包含一个 JSON 对象(比如 HTTP 500 的错误细节),这时我们就需要查看响应的状态码了r.status_code或r.raise_for_status(),成功调用时r.status_code为 200,r.raise_for_status()为 None。
自定义请求头:
当我们要给请求添加 headers 时,只需给 headers
参数传递一个字典即可,示例如下:
url = 'http://xxx.xxx'
hds= {'user-agent': 'xxx'}
r = requests.get(url, headers=hds)
注
:自定义 headers 优先级是低于一些特定的信息的,如:在 .netrc
中设置了用户认证信息,使用 headers 设置的授权就不会生效,而当设置了 auth
参数,.netrc
的设置会无效。所有的 headers 值必须是 string、bytestring 或者 unicode,通常不建议使用 unicode。
重定向与历史:
默认情况下,Requests 会自动处理除了 HEAD 以外的所有重定向,可以使用响应对象的 history
属性来追踪重定向,其返回为响应对象列表,这个列表是按照请求由晚到早进行排序的,看一下示例:
import requests
r = requests.get('http://github.com')
print(r.history)
# 输出结果
# [<Response [301]>]
如果使用的是get、post、put、delete、options、patch 可以使用 allow_redirects
参数禁用重定向。示例如下:
r = requests.get('http://xxx.xxx', allow_redirects=False)
错误与异常:
当遇到网络问题(如:DNS 查询失败、拒绝连接等)时,Requests 会抛出 ConnectionError 异常;在 HTTP 请求返回了不成功的状态码时, Response.raise_for_status() 会抛出 HTTPError 异常;请求超时,会抛出 Timeout 异常;请求超过了设定的最大重定向次数,会抛出 TooManyRedirects 异常。所有 Requests 显式抛出的异常都继承自 requests.exceptions.RequestException。
2、tkinter库
tkinter包(“Tk接口”)是Tcl/Tk GUI工具包的标准Python接口。
tkinter 的介绍 : http://en.wikipedia.org/wiki/tkinter
官方文档:tkinter — Python interface to Tcl/Tk — Python 3.10.7 documentation
TkDocs:TkDocs Home
tkinter的三种布局方式
Place:指定控件的位置和大小;是tkinter中最简单的布局管理器,它允许用户显式地设置窗口的大小和位置,无论是绝对值,或相对于另一个窗口。Place方法对所有基础控件都是可用的。
Pack:打包控件为一行或一列;Pack布局管理器将所有控件简单组织为一行或一列,用户可以使用expand,fill,both等选项对控件的样式进行控制。
Grid:按网格组织控件;Grid布局管理器将所有控件分布在一个二维的表格中,宿主控件将内部空间按行和列分割成若干单元格,然后每一个单元格内可以放置一个控件。
注意:官方不推荐使用Place布局管理器而建议都使用Grid布局管理器;另外Pack和Grid同时使用可能会导致程序的崩溃。
基础组件介绍:
Label:标签
Button:按钮
Checkbutton:单选按钮
Radiobutton:多选按钮
Entry:输入框
Text:文本框
Scrollbar:滚动条
Listbox:列表框
Frame:框架
LabelFrame:框起来的框架
Scale:范围滚动选择确切值
支持绘制图形:
arc:弧形、弦或扇形
bitmap:内建的位图文件或XBM格式的文件
image:BitmapImage 或 PhotoImage的实例对象
line:线
oval:圆或椭圆形
polygon:多边形
rectangle:矩形
text:文本
window:组件
3、Selenium框架
Selenium 是一个用于测试 Web 应用程序的框架,该框架测试直接在浏览器中运行,就像真实用户操作一样。它支持多种平台:Windows、Linux、Mac,支持多种语言:Python、Perl、PHP、C# 等,支持多种浏览器:Chrome、IE、Firefox、Safari 等。
安装 Selenium:
pip install selenium
安装 WebDriver:
主要浏览器 WebDriver 地址如下:
Chrome:http://chromedriver.storage.googleapis.com/index.html
Firefox:https://github.com/mozilla/geckodriver/releases/
IE:http://selenium-release.storage.googleapis.com/index.html
本文以 Chrome 为例,本机为 Windows 系统,WebDriver 使用版本 78.0.3904.11
,Chrome 浏览器版本为 78.0.3880.4
驱动程序下载好后解压,将 chromedriver.exe 放到 Python 安装目录下即可。
打开浏览器:
以打开去 163 邮箱为例:
from selenium import webdriver
#使用 Chrome 浏览器
browser = webdriver.Chrome()
browser.get('https://mail.163.com/')
#使用 Firefox 浏览器
browser = webdriver.Firefox()
browser.get('https://mail.163.com/')
#使用 IE 浏览器
browser = webdriver.Ie()
browser.get('https://mail.163.com/')
打开浏览器同时加载用户配置:
如果执行时报错没有打开指定页面,可先将浏览器关闭再执行。
from selenium import webdriver
#加载用户配置
option = webdriver.ChromeOptions()
option.add_argument('--user-data-dir=C:/Users/admin/AppData/Local/Google/Chrome/User Data')
#启动浏览器,获取网页源代码
browser = webdriver.Chrome(chrome_options=option)
browser.get('https://mail.163.com/')
# 关闭
browser.quit()
Headless 方式:
前两种方式都是有浏览器界面的方式,Headless 模式是 Chrome 浏览器的无界面形态,可以在不打开浏览器的前提下,使用所有 Chrome 支持的特性运行我们的程序。这种方式更加方便测试 Web 应用、获得网站的截图、做爬虫抓取信息等。看下示例:
from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
# 使用 headless 无界面浏览器模式
chrome_options.add_argument('--headless')
# 禁用 gpu 加速
chrome_options.add_argument('--disable-gpu')
# 启动浏览器,获取网页源代码
browser = webdriver.Chrome(chrome_options=chrome_options)
url = 'https://mail.163.com/'
browser.get(url)
print('browser text = ',browser.page_source)
browser.quit()
元素定位:
当我们想要操作一个元素时,首先需要找到它,Selenium 提供了多种元素定位方式,我们以 Chrome 浏览器 Headless 方式为例。看下示例:
from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
browser = webdriver.Chrome(chrome_options=chrome_options)
browser.get('https://xxx.xxx.com/')
data = browser.page_source
假设访问地址 https://xxx.xxx.com/
,返回 data
为如下内容。
<html>
<body>
<form>
<input id="fid" name="fid" type="text" />
<input id="firstName" name="fname" class="fname" type="text" />
<input id="lastName" name="fname" class="fname" type="text" />
<a href="index.html">index</a>
</form>
</body>
<html>
#根据id定位,返回该元素
browser.find_element_by_id('fid')
#根据 name 定位
# 返回第一个元素
browser.find_element_by_name('fname')
# 返回所有元素
browser.find_elements_by_name('fname')
#根据 class 定位
# 返回第一个元素
browser.find_element_by_class_name('fname')
# 返回所有元素
browser.find_elements_by_class_name('fname')
#根据标签名定位
# 返回第一个元素
browser.find_element_by_tag_name('input')
# 返回所有元素
browser.find_elements_by_tag_name('input')
#使用 CSS 定位
# 返回第一个元素
browser.find_element_by_css_selector('.fname')
# 返回所有元素
browser.find_elements_by_css_selector('.fname')
#使用链接文本定位超链接
# 返回第一个元素
browser.find_element_by_link_text('index')
# 返回所有元素
browser.find_elements_by_link_text('index')
# 返回第一个元素
browser.find_element_by_partial_link_text('index')
# 返回所有元素
browser.find_elements_by_partial_link_text('index')
#使用 xpath 定位
# 返回第一个元素
browser.find_elements_by_xpath("//input[@id='fid']")
# 返回所有元素
browser.find_elements_by_xpath("//input[@name='fname']")
4、Matplotlib库
Matplotlib 是 Python 提供的一个绘图库,通过该库我们可以很容易的绘制出折线图、直方图、散点图、饼图等丰富的统计图,安装使用 pip install matplotlib
命令即可,Matplotlib 经常会与 NumPy 一起使用。
我们在使用中文时可能会现乱码的问题,可以通过如下方式解决:
① 下载 SimHei.ttf,放到 site-packages\matplotlib\mpl-data\fonts\ttf 目录下
② 到 site-packages\matplotlib\mpl-data 目录下找到 matplotlibrc 文件,并修改如下两项即可
font.sans-serif : SimHei, DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif
axes.unicode_minus : False
绘制折线:
from matplotlib import pyplot as plt
x = range(1, 7)
y = [13, 15, 14, 16, 15, 17]
'''
figsize:设置图片的宽、高,单位为英寸
dpi:设置分辨率
'''
plt.figure(figsize=(8, 5), dpi=80)
plt.title('折线图')
plt.xlabel('x 轴')
plt.ylabel('y 轴')
'''
color:颜色
linewidth:线的宽度
marker:折点样式
linestyle:线的样式,主要包括:'-'、'--'、'-.'、':'
'''
plt.plot(x, y, color='red', marker='o', linewidth='1', linestyle='--')
# 保存
# plt.savefig('test.png')
plt.show()
输出效果:
绘制多线:
from matplotlib import pyplot as plt
x = range(15, 25)
y1 = [50, 55, 58, 65, 70, 68, 70, 72, 75, 70]
y2 = [52, 53, 60, 63, 65, 68, 75, 80, 85, 72]
plt.figure(figsize=(10, 6), dpi=80)
plt.title('体重年龄折线图')
plt.xlabel('年龄(岁)')
plt.ylabel('体重(kg)')
plt.plot(x, y1, color='red', label='张三')
plt.plot(x, y2, color='blue', label='李四')
# 添加网格,alpha 为透明度
plt.grid(alpha=0.5)
# 添加图例
plt.legend(loc='upper right')
plt.show()
输出效果:
绘制多个子图:
from matplotlib import pyplot as plt
import numpy as np
a = np.arange(1, 30)
# 划分子图
fig, axs = plt.subplots(2, 2)
# 绘制子图
axs1 = axs[0, 0]
axs2 = axs[0, 1]
axs3 = axs[1, 0]
axs4 = axs[1, 1]
axs1.plot(a, a)
axs2.plot(a, np.sin(a))
axs3.plot(a, np.log(a))
axs4.plot(a, a ** 2)
plt.show()
输出效果:
绘制散点图:
from matplotlib import pyplot as plt
import numpy as np
x = np.arange(0, 20)
# 生成随机数
y = np.random.randint(0, 20, size=20)
plt.title('散点图')
plt.xlabel('x 轴')
plt.ylabel('y 轴')
plt.plot(x, y, 'ob')
plt.show()
输出效果:
绘制直方图,示例如下:
import matplotlib.pyplot as plt
import numpy as np
# 生成随机数
d1 = np.random.randn(5000)
d2 = np.random.randn(4000)
'''
bins:直方图条目数
alpha:透明度
label:图例名
'''
plt.hist(d1, bins=50, label = 'label1', alpha=0.8)
plt.hist(d2, bins=50, label = 'label2', alpha=0.5)
plt.grid(alpha=0.3)
plt.title('直方图')
plt.xlabel('x 轴')
plt.ylabel('y 轴')
# 显示图例
plt.legend()
plt.show()
输出效果:
绘制条形图:
import matplotlib.pyplot as plt
import numpy as np
arr = np.arange(4)
x = ['张三', '李四', '王五', '赵六']
y = [77, 79, 70, 70]
# width:长条形宽度, label:图例名
rects = plt.bar(arr, y, width=0.3, label='语文')
# 参数1:中点坐标,参数2:显示值
plt.xticks([idx for idx in range(len(x))], x)
plt.title('学生成绩条形图')
plt.xlabel('姓名')
plt.ylabel('成绩')
plt.legend()
# 在条形图上加标注
for rect in rects:
height = rect.get_height()
plt.text(rect.get_x() + rect.get_width() / 2, height, str(height), ha='center', va='bottom')
plt.show()
#横置条形图
arr = np.arange(4)
y = ['张三', '李四', '王五', '赵六']
x = [88, 79, 70, 66]
plt.barh(range(4), x, 0.4, label='语文')
plt.yticks(range(4), y)
plt.xlabel('成绩')
plt.ylabel('姓名')
plt.title('学生成绩条形图')
plt.legend(loc='upper right')
for x, y in enumerate(x):
plt.text(y + 0.2, x - 0.1, '%s' % y)
plt.show()
输出效果:
绘制多条条形图:
import matplotlib.pyplot as plt
import numpy as np
arr = np.arange(4)
x = ['张三', '李四', '王五', '赵六']
y1 = [88, 75, 77, 66]
y2 = [77, 79, 70, 70]
'''
width:长条形宽度
label:图例名
'''
rects1 = plt.bar(arr, y1, width=0.3, label='语文')
rects2 = plt.bar(arr + 0.3, y2, width=0.3, label='数学')
'''
参数1:中点坐标
参数2:显示值
参数3:间距
'''
plt.xticks([idx + 0.15 for idx in range(len(x))], x, rotation=10)
plt.title('学生成绩条形图')
plt.xlabel('姓名')
plt.ylabel('成绩')
plt.legend()
# 编辑文本
for rect in rects1:
height = rect.get_height()
plt.text(rect.get_x() + rect.get_width() / 2, height, str(height), ha='center', va='bottom')
for rect in rects2:
height = rect.get_height()
plt.text(rect.get_x() + rect.get_width() / 2, height, str(height), ha='center', va='bottom')
plt.show()
输出效果:
绘制饼状图:
import matplotlib.pyplot as plt
label_list = ['第一部分', '第二部分', '第三部分']
size = [50, 30, 20]
# 各部分颜色
color = ['red', 'green', 'blue']
# 各部分突出值
explode = [0, 0.1, 0]
'''
explode:设置各部分突出
label:设置图例显示内容
labeldistance:设置图例内容距圆心位置
autopct:设置圆里面文本
shadow:设置是否有阴影
startangle:起始角度,默认从 0 开始逆时针转
pctdistance:设置圆内文本距圆心距离
l_text:圆内部文本
p_text:圆外部文本
'''
patches, l_text, p_text = plt.pie(size, explode=explode, colors=color, labels=label_list, labeldistance=1.1, autopct="%1.1f%%", shadow=False, startangle=90, pctdistance=0.6)
# 设置横轴和纵轴大小相等,这样饼才是圆的
plt.axis('equal')
plt.legend(loc='upper left')
plt.show()
输出效果:
四、笔记
1、C++对Python的调用
Python 提供了一套 C API库,使得开发者能很方便地从C/ C++ 程序中调用 Python 模块。
举个栗子:
Python模块名为"common.py",代码如下:
def add(a, b):
print('a: ', a)
print('b: ', b)
return a + b
C++代码如下:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <iostream>
int main(int, char **)
{
// 初始化python解释器
Py_Initialize();
if (!Py_IsInitialized())
{
return -1;
}
// 添加编译后文件的所在路径
PyRun_SimpleString("import sys"); //运行的Python语句以字符串的形式传递给Python解释器
PyRun_SimpleString("sys.path.append('./')");
// 要调用的python文件名
auto pModule = PyImport_ImportModule("common"); // 记得复制到编译后文件的路径下,同时不用加后缀名“.py“
if (!pModule)
{
std::cout << "Can't find your xx.py file.";
getchar();
return -1;
}
//获取模块中的函数
auto pFunc = PyObject_GetAttrString(pModule, "add"); //从字符串创建python函数对象
// 参数类型转换
PyObject *pArg = Py_BuildValue("ii", 1, 2);
//调用直接获得的函数,并传递参数
auto *py_result = PyEval_CallObject(pFunc, pArg);
int c_result;
// 将python类型的返回值转换为C类型
PyArg_Parse(py_result, "i", &c_result);
std::cout << "return: " << c_result << std::endl;
};