14天学习训练营导师课程:
李宁《Python Pygame游戏开发入门与实战》
李宁《计算机视觉OpenCV Python项目实战》1
李宁《计算机视觉OpenCV Python项目实战》2
李宁《计算机视觉OpenCV Python项目实战》3
本文档整理自李宁老师发布在B站的视频,主要介绍python相关的基础入门知识,相关代码和本文档(md格式)提取码:pyth
import sys
# 将模块所在的路径添加到sys.path列表中
sys.path.append('./test')
print(sys.path)
import my
my.greet('Bill')
print(sys.modules['my'])
print(type(sys.modules['my']))
print(sys.platform)
# 命令行参数
# 使用cmd切换到当前文件的路径,输入:python demo12.1.py abc,'abc'就是传入的命令行参数
# 或者在Pycharm中调出下方的Terminal,输入python demo12.1.py abc
# 输出当前脚本文件的完整路径
print(sys.argv[0])
if len(sys.argv) == 2:
print(sys.argv[1])
my.greet(sys.argv[1])
print('------------------------')
# 标准的输入输出流
s = sys.stdin.read(6) # 只读取输入的前6个字符
print(s) # 输出读取的字符
sys.stdout.writelines('hello world')
sys.stderr.writelines('error') # 用红色标记错误输出,而且该行输出的位置是不确定的,可以多运行几次程序观察结果
# 当本脚本被调用时,会输出123,可以运行invoke.py查看运行结果
sys.exit(123)
# 下面是从pycharm控制台运行demo12.1.py的结果
PS D:\Projects\Python\test\demo12_Modules> python demo12.1.py abc
['D:\\Projects\\Python\\test\\demo12_Modules','test'] # 该列表还包含其他路径,这里不作展示,新添加的路径在列表的末尾,即'test'
hello Bill
<module 'my' from 'D:\\Projects\\Python\\test\\demo12_Modules\\./test\\my.py'>
<class 'module'>
win32
demo12.1.py
abc
hello abc
------------------------
请输入一段长度大于6的字符串: asigyhas
asigyh
hello worlderror
invoke.py文件中的代码
import subprocess
output = subprocess.getstatusoutput('python demo12.1.py Harry')
import pprint
pp = pprint.PrettyPrinter(indent=1)
pp.pprint(output)
# 先输出123,再输出demo12.1.py的调用结果
print(output[0])
import os
print(f"当前工作目录:{os.getcwd()}")
# 获取当前工作目录中的文件名和目录名
print(os.listdir(os.getcwd()))
os.chdir('../')
print(f"改变后的工作目录:{os.getcwd()}")
print(os.listdir(os.getcwd()))
当前工作目录:D:\Projects\Java\py2Md\target
['bill', 'classes', 'generated-sources', 'lib', 'maven-archiver', 'maven-status', 'Py2Md-1.0-SNAPSHOT.jar', 'Py2Md.exe', 'yourdir']
改变后的工作目录:D:\Projects\Java\py2Md
['.git', '.gitignore', '.idea', 'pom.xml', 'README.md', 'src', 'target']
'''
1、mkdir(dirname, permissions)
r w x
如果dirname存在,会抛出OSError
2、makedirs(dirname, permissions, exist_ok)
(1)创建多级目录 mkdir('a') mkdir('a/b')(如果上级目录a不存在,下级目录b也不会创建)
makedirs('a/b/c') 可以连续创建这三个目录
(2) exist_ok == False,如果目录存在,会抛出OSError
exist_ok == True,如果目录存在,不会进行任何操作
3、rmdir(dirname):删除目录
rmdir('a') 如果目录a不为空,会抛出OSError
4、removedirs(dirname):删除目录,可以指定多级目录
removedirs('a/b/c') 如果几层目录均为空,会全部删除
5、remove(filename)删除filename指定的文件
6、rename(src, dst) 将src参数指定的文件改名为dst指定的文件名
7、renames(src, dst)
a/b/c --> x/y/z 可以同时修改多层目录的名称
'''
# 建议跟着视频一步一步运行该文件
import os
if not os.path.exists('newdir1'):
os.mkdir('newdir1')
os.makedirs('x/y/z', 0o733, True)
try:
os.rmdir('newdir1')
except OSError as e:
print(e)
# os.removedirs('x/y/z')
if not os.path.exists('mydir'):
os.mkdir('mydir')
os.rename('mydir', 'yourdir')
if os.path.exists('x/y/z'):
os.renames('x/y/z', 'bill/mike/john')
if os.path.exists('newdir1/a.txt'):
os.remove('newdir1/a.txt')
'''
软链接(符号链接):相当于Windows的快捷方式
硬链接:是文件的副本
'''
import os
# windows系统要实现软链接需要开启特权SeCreateSymbolicLinkPrivilege
# if os.path.exists('data.txt') and not os.path.exists('slink_data.txt'):
# # 建立软链接文件
# os.symlink('data.txt', 'slink_data.txt')
if os.path.exists('data.txt') and not os.path.exists('link_data.txt'):
# 建立硬链接文件
os.link('data.txt', 'link_data.txt')
'''
1、sep变量:返回当前OS的路径分隔符
2、pathsep变量:返回环境变量中的路径之间的分隔符
3、name变量:返回当前OS的名称
4、environ变量:以字典的形式返回系统中所有环境变量的值
5、getenv函数:获取指定的环境变量的值,通过参数可以指定环境变量名
6、putenv函数:设置指定环境变量的值,通过参数指定环境变量名和环境变量值
7、system函数:执行命令,通过参数指定要执行的命令
'''
import os
import subprocess
print('路径分隔符', os.sep)
print('环境变量路径之间的分隔符', os.pathsep)
print('操作系统名', os.name)
print(os.environ)
print('PATH=', os.environ['PATH'])
print('PATH=', os.getenv('PATH'))
路径分隔符 \
环境变量路径之间的分隔符 ;
'''
集合满足:
1、无序性:集合中各个元素的值是平等的
2、互异性:集合中任意两个元素都是不同的,每个元素只能出现一次
3、确定性:集合中每个元素都是确定的,对于某个值来说,要么属于该集合,要么不属于该集合。
列表、字典都不能作为集合的元素值,因为它们都是可变的
'''
set1 = set(range(10))
print(set1)
set2 = set('helloabc') # 自动去除重复字符
print(set2)
set3 = set(['Bill', 'John', 'Mike', 'John'])
print(set3)
print('--------------------------')
# 求a和b的并集
a = set((1, 2, 3))
b = set([3, 5, 1, 6])
print(a.union(b))
print(a | b)
# 求a和b的交集
print(a.intersection(b))
print(a & b)
c = set([2, 3])
print(c.issubset(a))
print(a.issubset(c))
print(a.issuperset(c))
d = set([1, 2, 3])
print(a == d)
# 计算集合的差
print(a.difference(b))
print(a - b)
# 计算集合的对称差:只在其中一个集合出现的元素组成的集合
print(a.symmetric_difference(b))
print(a ^ b)
print((a - b) | (b - a))
x = a.copy()
y = a
print(y is a)
print(x is a)
print(1 in a)
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
{'h', 'c', 'a', 'l', 'o', 'b', 'e'}
{'Mike', 'John', 'Bill'}
--------------------------
{1, 2, 3, 5, 6}
{1, 2, 3, 5, 6}
{1, 3}
{1, 3}
True
False
True
True
{2}
{2}
{2, 5, 6}
{2, 5, 6}
{2, 5, 6}
True
False
True
'''
集合的元素和字典中的key都不允许是可变的对象,如集合、列表和字典
元组既可以做集合的元素,也可以做字典的key
'''
aSet = set([1, 2])
bSet = set([10, 20])
aSet.add(4)
print(aSet)
# a.add(b) # 直接将集合作为元素添加到另一个集合,会报错
aSet.add(frozenset(bSet)) # frozenset()只读取集合
print(aSet)
dict = {'Bill': 30, 'Mike': 34}
# d[a] = 10 # 不能直接将集合作为key输入字典中
dict[frozenset(aSet)] = 10
print(dict)
# bSet.add(dict) # 集合不能添加可变对象,如字典
t = (1,2,3,4)
bSet.add(t)
print(bSet)
{1, 2, 4}
{1, 2, 4, frozenset({10, 20})}
{'Bill': 30, 'Mike': 34, frozenset({1, 2, 4, frozenset({10, 20})}): 10}
{(1, 2, 3, 4), 10, 20}
from heapq import *
from random import *
data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
heap = []
for n in data:
value = choice(data) # 从data中随机选取一个元素
# 将值添加到堆
heappush(heap, value)
print(heap)
heappush(heap, 30)
print(heap)
print(heappop(heap)) # 弹出最小值
data1 = [6,3,1,12,9]
heapify(data1)
print(data1)
print(heapreplace(data1, 123)) # 弹出最小值,并替换为123
print(data1)
print(nlargest(2, data1)) # 返回data1中的最大的n个值
print(nsmallest(3,data1))
print(list(merge([1,3,456,7],[0,1,-5,6],[1,7,4],[],[67])))
print(list(merge(['dog','horse'],['cat','fish','kangaroo'],key=len)))
[1, 2, 2, 4, 5, 5, 5, 9, 6]
[1, 2, 2, 4, 5, 5, 5, 9, 6, 30]
1
[1, 3, 6, 12, 9]
1
[3, 9, 6, 12, 123]
[123, 12]
[3, 6, 9]
[0, 1, 1, -5, 1, 3, 6, 7, 4, 67, 456, 7]
['dog', 'cat', 'fish', 'horse', 'kangaroo']
from collections import deque
q = deque(range(10))
print(q)
# 在两端添加元素
q.append(123)
q.append(-32)
print(q)
q.appendleft(30)
print(q)
# 在两端弹出元素
print(q.pop())
print(q)
print(q.popleft())
print(q)
# 将q向左循环移动2个位置
q.rotate(-2)
print(q)
q.rotate(4)
print(q)
q1 = deque(['a','b'])
q.extend(q1)
print(q)
q.extendleft(q1)
print(q)
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 123, -32])
deque([30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 123, -32])
-32
deque([30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 123])
30
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 123])
deque([2, 3, 4, 5, 6, 7, 8, 9, 123, 0, 1])
deque([9, 123, 0, 1, 2, 3, 4, 5, 6, 7, 8])
deque([9, 123, 0, 1, 2, 3, 4, 5, 6, 7, 8, 'a', 'b'])
deque(['b', 'a', 9, 123, 0, 1, 2, 3, 4, 5, 6, 7, 8, 'a', 'b'])
import time
localtime = time.localtime(time.time())
print(f"当前时间是:{localtime}")
print(type(localtime)) # localtime是一个对象
st = time.struct_time((1,2,3,4,5,6,7,8,9)) # 参数需要是含有9个元素的元组
print(st)
print(f"年 = {localtime.tm_year}")
print(f"月 = {localtime.tm_mon}")
print(f"日 = {localtime.tm_mday}")
print(f"一年的第{localtime[7]}天")
localtime = time.asctime(localtime)
print(localtime)
当前时间是:time.struct_time(tm_year=2021, tm_mon=11, tm_mday=10, tm_hour=21, tm_min=27, tm_sec=52, tm_wday=2, tm_yday=314, tm_isdst=0)
<class 'time.struct_time'>
time.struct_time(tm_year=1, tm_mon=2, tm_mday=3, tm_hour=4, tm_min=5, tm_sec=6, tm_wday=7, tm_yday=8, tm_isdst=9)
年 = 2021
月 = 11
日 = 10
一年的第314天
Wed Nov 10 21:27:52 2021
'''
strftime: 参数1:格式化字符串 参数2:时间元祖
'''
import time
import locale
locale.setlocale(locale.LC_ALL, 'zh_CN.UTF-8')
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
print(time.strftime('%Y年%m月%d日 %H时%M分%S秒', time.localtime()))
# 输出星期的完整名称
print(time.strftime("今天是%A",time.localtime()))
2021-11-10 21:27:52
2021年11月10日 21时27分52秒
今天是星期三
import time
time1 = time.time()
time2 = time1 + 60
print(time2)
time3 = time1 + 60*60
time3 = time.localtime(time3)
print(time3)
print(time.strftime('%Y-%m-%d %H:%M:%S', time3))
1636550932.8739896
time.struct_time(tm_year=2021, tm_mon=11, tm_mday=10, tm_hour=22, tm_min=27, tm_sec=52, tm_wday=2, tm_yday=314, tm_isdst=0)
2021-11-10 22:27:52
import datetime
d1 = datetime.datetime(2017,4,12)
d2 = datetime.datetime(2018,12,25)
print((d2-d1).days)
d1 = datetime.datetime(2017,4,12,10,10,10)
d2 = datetime.datetime(2018,12,25,10,10,40)
print(d2-d1)
print((d2-d1).seconds)
d1 = datetime.datetime.now()
d2 = d1 + datetime.timedelta(hours = 10)
print(d2)
d2 = d1 + datetime.timedelta(hours = -10)
print(d2)
622
622 days, 0:00:30
30
2021-11-11 07:27:52.988998
2021-11-10 11:27:52.988998
import calendar
import locale
cal = calendar.month(2021,1)
print(cal)
print(calendar.calendar(2021))
January 2021
Mo Tu We Th Fr Sa Su
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
2021
January February March
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 6 7
4 5 6 7 8 9 10 8 9 10 11 12 13 14 8 9 10 11 12 13 14
11 12 13 14 15 16 17 15 16 17 18 19 20 21 15 16 17 18 19 20 21
18 19 20 21 22 23 24 22 23 24 25 26 27 28 22 23 24 25 26 27 28
25 26 27 28 29 30 31 29 30 31
April May June
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 1 2 1 2 3 4 5 6
5 6 7 8 9 10 11 3 4 5 6 7 8 9 7 8 9 10 11 12 13
12 13 14 15 16 17 18 10 11 12 13 14 15 16 14 15 16 17 18 19 20
19 20 21 22 23 24 25 17 18 19 20 21 22 23 21 22 23 24 25 26 27
26 27 28 29 30 24 25 26 27 28 29 30 28 29 30
31
July August September
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 1 1 2 3 4 5
5 6 7 8 9 10 11 2 3 4 5 6 7 8 6 7 8 9 10 11 12
12 13 14 15 16 17 18 9 10 11 12 13 14 15 13 14 15 16 17 18 19
19 20 21 22 23 24 25 16 17 18 19 20 21 22 20 21 22 23 24 25 26
26 27 28 29 30 31 23 24 25 26 27 28 29 27 28 29 30
30 31
October November December
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 1 2 3 4 5 6 7 1 2 3 4 5
4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12
11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19
18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26
25 26 27 28 29 30 31 29 30 27 28 29 30 31
'''
randint(m,n):用于产生m到n之间的随机整数,包括m和n
random():用于产生0到1之间的随机浮点数,包括0,但不包括1
uniform(m,n):用于产生m到n之间的随机浮点数,m和n可以是浮点数,包括m和n
randrange(m,n,step):在一个递增的序列中随机选择一个整数。其中step是步长
如randrange(1,6,2)会在列表[1,3,5]中随机选择一个整数
choice(seq):从seq序列中随机选择一个元素值。seq指定的列表元素可以是任意类型的值
sample(seq,k):从seq中随机选出k个元素,然后生成一个新的序列
shuffle(seq):把seq序列中的元素顺序打乱,该函数直接修改原有的序列
'''
import random
print(random.randint(1,100))
print(random.random())
print(random.randrange(1,20,3)) # 从[1,4,7,10,13,16,19]中选取
print(random.uniform(1,100.05))
intList = [1,2,5,7,39,40]
print(random.choice(intList))
newList = random.sample(intList, 3)
print(newList)
random.shuffle(intList)
print(intList)
58
0.44714554718797783
10
81.96900990017868
5
[40, 39, 2]
[40, 7, 39, 1, 2, 5]
import math
print('圆周率 =',math.pi)
print('自然常数 =', math.e)
print(math.fabs(-1.2))
# 向上取整
print(math.ceil(1.3))
# 向下取整
print(math.floor(1.8))
print(math.pow(2, 10))
print(math.sqrt(8))
print(math.sin(math.pi/2))
print(math.cos(math.pi))
print(math.tan(math.pi/4))
圆周率 = 3.141592653589793
自然常数 = 2.718281828459045
1.2
2
1
1024.0
2.8284271247461903
1.0
-1.0
0.9999999999999999
'''
1、读文件和写文件
2、管道输出
3、读行和写行
4、使用FileInput对象读取文件
'''
'''
r:读 w:写
r+:文件可读写,如果文件不存在,会抛出异常。如果文件存在,会从当前位置开始写入新内容
通过seek函数可以改变当前的位置,即改变文件的指针
w+:文件可读写,如果文件不存在,会创建一个新文件,如果文件存在,会清空原文件,并写入新内容
a+:文件可读写,如果文件不存在,会创建一个新文件,如果文件存在,会将新内容添加到原文件的最后
使用a+打开文件,文件指针会在文本的最后
'''
'''
write(string):向文件写入内容,会返回写入文件的字节数
read(n):读取文件内容,n是一个整数,表示从文件指针指定位置开始读取的n个字节
不指定n,会读取从当前位置往后的所有字节。该函数会返回读取的内容
seek(n):重新设置文件指针,也就是改变文件的当前位置。如果使用write函数写入内容后,
需要使用seek(0)重置文件指针
close():关闭文件,对文件进行读写操作后,关闭文件是一个好习惯
'''
f = open('./files/test1.txt','w')
print(f.write('I love '))
print(f.write('python'))
f.close()
f = open('./files/test1.txt', 'r')
print(f.read(7))
print(f.read(6))
f.close()
try:
f = open('./files/test2.txt', 'r+') # 尝试打开不存在的文件
except Exception as e:
print(e)
f = open('./files/test2.txt', 'a+')
print(f.write('hello'))
f.close()
print('-------------1------------')
f = open('./files/test2.txt', 'a+')
print(f.read())
f.seek(0)
print('-------------2-------------')
print(f.read())
f.close()
try:
f = open('./files/test2.txt', 'w+')
print(f.read())
f.write('How are you?')
f.seek(0)
print(f.read())
finally:
f.close()
7
6
I love
python
[Errno 2] No such file or directory: './files/test2.txt'
5
-------------1------------
-------------2-------------
hello
How are you?
f = open('./files/urls.txt', 'r+')
url = ''
while True:
url = f.readline()
url = url.rstrip() # 去掉每一行末尾的换行符
if url == '':
break
else:
print(url)
print('---------------------------')
f.seek(0)
# windows系统下,调用os.linesep会添加两个换行符
print(f.readlines())
f.write('http://baidu.com'+'\n')
f.close()
f = open('./files/urls.txt', 'a+')
urlList = ['https://google.com'+'\n','https://jd.com']
f.writelines(urlList)
f.close()
https://geekori.com
https://geekori.com/que.php
http://ningedu.com
---------------------------
['https://geekori.com\n', 'https://geekori.com/que.php\n', 'http://ningedu.com\n']
import fileinput
fileobj = fileinput.input('./files/urls.txt')
print(type(fileobj))
print(fileobj.readline().rstrip())
for line in fileobj:
line = line.rstrip()
if line != '':
print(fileobj.lineno(), ':', line) # 输出行号
else:
print(fileobj.filename())
<class 'fileinput.FileInput'>
https://geekori.com
2 : https://geekori.com/que.php
3 : http://ningedu.com
'''
编写一个程序,从控制台输入一个奇数
然后生成奇数行的星号(*)菱形,并将该菱形保存到当前目录下的stars.txt文件
'''
line = input('请输入行数(必须是奇数):')
line = int(line) # 这里的行数同时也是星号最多的一行中星号的个数
# 在当前目录下的stars.txt文件中查看输出结果
if line % 2 != 0:
f = open('stars.txt', 'w')
spaceNum = line // 2 # 第一行的星号左侧或右侧的空格个数
i = 1
lineSpaceNum = spaceNum
# 生成上三角形
while lineSpaceNum >= 0:
f.write(' ' * lineSpaceNum)
f.write('*' * (2*i-1))
f.write(' ' * lineSpaceNum + '\n')
lineSpaceNum -= 1
i += 1
i -= 2
lineSpaceNum += 2
# 生成下三角形
while lineSpaceNum <= spaceNum:
f.write(' ' * lineSpaceNum)
f.write('*' * (2 * i - 1))
f.write(' ' * lineSpaceNum + '\n')
lineSpaceNum += 1
i -= 1
f.close()
else:
print('必须输入奇数!')
请输入行数(必须是奇数):11
# 在star.txt中可查看
*
***
*****
*******
*********
***********
*********
*******
*****
***
*
'''
编写程序,从当前目录的文本文件words.txt中读取所有内容(全都是英文单词),并统计其中每个英文单词出现的次数。
单词之间用逗号、分号或空格分隔,也可能是这3个分隔符一起分隔单词。将统计结果保存到字典中,并输出统计结果。
'''
import re
f = open('words.txt', 'r')
words = f.read()
wordList = re.split('[ ,;]+', words)
print(wordList)
countDict = {}
for word in wordList:
if countDict.get(word) == None:
countDict[word] = 1
else:
countDict[word] += 1
for (key, value) in countDict.items():
print(key, '=', value)
f.close()
['test', 'star', 'test', 'star', 'star', 'bus', 'test', 'bill', 'new', 'yeah', 'bill', 'book', 'bike', 'God', 'start', 'python', 'what']
test = 3
star = 3
bus = 1
bill = 2
new = 1
yeah = 1
book = 1
bike = 1
God = 1
start = 1
python = 1
what = 1
'''
1. XML
2. JSON
3. SQLite
4. MySQL
5. ORM(SQLAlchemy SQLObject)
6. 非关系型数据库(NoSQL) MongoDB
'''
# 读取与检索XML文件
from xml.etree.ElementTree import parse
doc = parse('files/products.xml')
for item in doc.iterfind('products/product'):
# 读取id、name、price节点的值
id = item.findtext('id')
name = item.findtext('name')
price = item.findtext('price')
uuid = item.get('uuid')
print('uudi =', uuid)
print('id =', id)
print('name =', name)
print('price =', price)
print('---------------------')
uudi = 1234
id = 10000
name = iPhone9
price = 9999
---------------------
uudi = 4321
id = 20000
name = 特斯拉
price = 1000000
---------------------
uudi = 5678
id = 30000
name = Mac Pro
price = 40000
---------------------
# pip install dicttoxml
import os
import dicttoxml
from xml.dom.minidom import parseString
d = [20,'names',{'name':'Bill','age':30,'salary':20000},
{'name':'李宁','age':123,'salary':30000},
{'name':'John','age':29,'salary':8000}
]
# 将字典转换为XML格式(bytes形式)
bxml = dicttoxml.dicttoxml(d, custom_root = 'persons')
# print(bxml) # python对中文字符进行了二进制编码
xml = bxml.decode('utf-8')
print(xml)
# 解析xml字符串
dom = parseString(xml)
prettyxml = dom.toprettyxml(indent = ' ')
print(prettyxml)
os.makedirs('files', exist_ok= True)
f = open('files/persons.xml', 'w', encoding= 'utf-8')
f.write(prettyxml)
f.close()
<?xml version="1.0" encoding="UTF-8" ?><persons><item type="int">20</item><item type="str">names</item><item type="dict"><name type="str">Bill</name><age type="int">30</age><salary type="int">20000</salary></item><item type="dict"><name type="str">李宁</name><age type="int">123</age><salary type="int">30000</salary></item><item type="dict"><name type="str">John</name><age type="int">29</age><salary type="int">8000</salary></item></persons>
<?xml version="1.0" ?>
<persons>
<item type="int">20</item>
<item type="str">names</item>
<item type="dict">
<name type="str">Bill</name>
<age type="int">30</age>
<salary type="int">20000</salary>
</item>
<item type="dict">
<name type="str">李宁</name>
<age type="int">123</age>
<salary type="int">30000</salary>
</item>
<item type="dict">
<name type="str">John</name>
<age type="int">29</age>
<salary type="int">8000</salary>
</item>
</persons>
import xmltodict
f = open('files/products.xml', 'rt', encoding='utf-8')
xml = f.read()
d = xmltodict.parse(xml) # 转换为一个嵌套的字典
# print(d)
for v in d['root']['products']['product']:
print('uuid :', v['@uuid'])
print('id :', v['id']) # 注意:id/name/price前不用加@
print('name :', v['name'])
print('price :', v['price'])
print('---------------')
print(d['root']['products']['product'][0]['@uuid'])
import pprint
pp = pprint.PrettyPrinter(indent=1)
pp.pprint(d)
uuid : 1234
id : 10000
name : iPhone9
price : 9999
---------------
uuid : 4321
id : 20000
name : 特斯拉
price : 1000000
---------------
uuid : 5678
id : 30000
name : Mac Pro
price : 40000
---------------
1234
OrderedDict([('root',
OrderedDict([('products',
OrderedDict([('product',
[OrderedDict([('@uuid', '1234'),
('id', '10000'),
('name', 'iPhone9'),
('price', '9999')]),
OrderedDict([('@uuid', '4321'),
('id', '20000'),
('name', '特斯拉'),
('price', '1000000')]),
OrderedDict([('@uuid', '5678'),
('id', '30000'),
('name', 'Mac Pro'),
('price',
'40000')])])]))]))])
'''
1、使用JSON模块的loads函数,该函数通过参数传入json字符串,然后返回与该字符串对应的字典
2、使用eval函数将json格式字符串当做普通的python代码执行,eval函数会直接返回与json格式字符串对应的字典
'''
import json
data = {
'name':'Bill',
'company':'Microsoft',
'age':34
}
# 将字典转换为json字符串
jsonstr = json.dumps(data)
print(type(jsonstr))
print(jsonstr)
# 将json字符串转换为字典
data = json.loads(jsonstr)
print(type(data))
print(data)
# 定义一个json字符串,要注意缩进,然后使用eval函数转换为字典
s = '''
{
'name':'Bill',
'company':'Microsoft',
'age':34
}
'''
data = eval(s) # 使用eval函数转换时,字符串可以使用单引号
print(type(data))
print(data)
f = open('files/products.json','r',encoding='utf-8')
jsonStr = f.read()
json1 = eval(jsonStr)
json2 = json.loads(jsonStr)
# json文件中字符串要使用双引号,使用单引号调用json.loads函数会报错
# json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes
print(json1)
print(json2)
<class 'str'>
{"name": "Bill", "company": "Microsoft", "age": 34}
<class 'dict'>
{'name': 'Bill', 'company': 'Microsoft', 'age': 34}
<class 'dict'>
{'name': 'Bill', 'company': 'Microsoft', 'age': 34}
[{'name': 'iPhone9', 'price': 9999, 'count': 2000}, {'name': '特斯拉', 'price': 1000000, 'count': 123}]
[{'name': 'iPhone9', 'price': 9999, 'count': 2000}, {'name': '特斯拉', 'price': 1000000, 'count': 123}]
'''
loads
loads函数的object_hook关键字指定一个类或一个回调函数
1、指定类:loads函数会自动创建指定的类的实例,并将有json字符串转换成的字典通过类的构造方法传入类实例
指定的类必须有一个可以接受字典的构造方法
2、指定为回调函数:loads函数会调用回调函数返回类的实例,并将由json字符串转换为的字典传入回调函数
回调函数必须有一个参数可以接受字典
'''
import json
class Product:
def __init__(self, d):
self.__dict__ = d
f = open('files/product.json', 'r')
jsonStr = f.read()
my1 = json.loads(jsonStr, object_hook=Product)
print(type(my1))
print('name = ',my1.name)
print('price = ',my1.price)
print('count = ',my1.count)
print('-----------------------')
# jsonStr -> Dict -> Product_object
def json2Product(d):
return Product(d)
my2 = json.loads(jsonStr, object_hook=json2Product)
print(my2)
print('name = ',my2.name)
print('price = ',my2.price)
print('count = ',my2.count)
f.close()
<class '__main__.Product'>
name = iPhone
price = 9999
count = 3000
-----------------------
<__main__.Product object at 0x00000238660EF0D0>
name = iPhone
price = 9999
count = 3000
'''
dumps:将字典转换为JSON字符串
default关键字参数指定一个回调函数,该回调函数会接受一个类实例
回调函数需要返回一个字典,最后,dumps函数将这个字典转换为JSON字符串
object -> dict -> JSON
'''
import json
class Product:
def __init__(self,name,price,count):
self.name = name
self.price = price
self.count = count
def product2Dict(obj):
return {
'name':obj.name,
'price':obj.price,
'count':obj.count
}
product = Product('特斯拉', 1000000, 20)
jsonStr = json.dumps(product, default= product2Dict, ensure_ascii=False)
print(jsonStr)
{"name": "特斯拉", "price": 1000000, "count": 20}
import json
class Product:
def __init__(self,d):
self.__dict__ = d
# JSON字符串转换为类实例
f = open('files/products.json','r',encoding='utf-8')
jsonStr = f.read()
products = json.loads(jsonStr, object_hook=Product)
print(type(products))
print(products) # products是一个列表,其元素是两个Product类对象
for product in products:
print('name =', product.name)
print('price =',product.price)
print('count =',product.count)
# 类实例对象转换为JSON字符串
def product2Dict(product):
return {
'name':product.name,
'price':product.price,
'count':product.count
}
jsonStr = json.dumps(products, default=product2Dict,ensure_ascii=False)
print(jsonStr)
f.close()
<class 'list'>
[<__main__.Product object at 0x000001CC7307FE80>, <__main__.Product object at 0x000001CC7307F7C0>]
name = iPhone9
price = 9999
count = 2000
name = 特斯拉
price = 1000000
count = 123
[{"name": "iPhone9", "price": 9999, "count": 2000}, {"name": "特斯拉", "price": 1000000, "count": 123}]
# json -> dict -> xml
import json
import dicttoxml
f = open('files/products.json','r',encoding='utf-8')
jsonStr = f.read()
d = json.loads(jsonStr)
print(d)
xmlStr = dicttoxml.dicttoxml(d).decode('utf-8')
print(xmlStr)
f.close()
[{'name': 'iPhone9', 'price': 9999, 'count': 2000}, {'name': '特斯拉', 'price': 1000000, 'count': 123}]
<?xml version="1.0" encoding="UTF-8" ?><root><item type="dict"><name type="str">iPhone9</name><price type="int">9999</price><count type="int">2000</count></item><item type="dict"><name type="str">特斯拉</name><price type="int">1000000</price><count type="int">123</count></item></root>
'''
安装SQLite:https://sqlite.org/download.html
安装教程参考:https://www.runoob.com/sqlite/sqlite-installation.html
下载DB Browser for SQLite:http://www.sqlitebrowser.org/?template=VERTICAL_LINES&tdfs=1&s_token=1636608497.0397460000&uuid=1636608497.0397460000&term=SQL%20Server%20Database%20Performance%20Monitoring%20Tools&term=ETL%20Tools%20Database%20Browser&term=SQL%20Database%20Programming&searchbox=0&showDomain=0&backfill=0
'''
import sqlite3
import os
dbPath = 'data.sqlite'
if not os.path.exists(dbPath):
conn = sqlite3.connect(dbPath)
c = conn.cursor()
c.execute('''CREATE TABLE persons
(id INT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
age INT NOT NULL,
address CHAR(50),
salary REAL);
''')
conn.commit() # 在当前目录下可查看新建的数据库
conn = sqlite3.connect(dbPath)
c = conn.cursor()
c.execute('delete from persons')
c.execute("insert into persons(id,name,age,address,salary)\
values(1,'Bill',32,'California',20000.50)")
c.execute("insert into persons(id,name,age,address,salary)\
values(2,'Mary',26,'Texas',1234)")
c.execute("insert into persons(id,name,age,address,salary)\
values(3,'Harry',29,'Norway',5865)")
c.execute("insert into persons(id,name,age,address,salary)\
values(4,'John',30,'Vegas',8353)")
conn.commit()
print('数据插入成功')
persons = c.execute('select name,age,address,salary from persons order by age')
print(type(persons))
result = []
for person in persons:
value = {}
value['name'] = person[0]
value['age'] = person[1]
value['address'] = person[2]
result.append(value)
conn.close()
print(result)
数据插入成功
<class 'sqlite3.Cursor'>
[{'name': 'Mary', 'age': 26, 'address': 'Texas'}, {'name': 'Harry', 'age': 29, 'address': 'Norway'}, {'name': 'John', 'age': 30, 'address': 'Vegas'}, {'name': 'Bill', 'age': 32, 'address': 'California'}]
'''
pip install pymysql
conda install pymysql
Document for Python DB API v2.0:https://www.python.org/dev/peps/pep-0249/
MySQL:https://dev.mysql.com/downloads/mysql/
安装教程:https://www.php.cn/mysql-tutorials-454993.html
'''
'''
connect函数:连接数据库,返回Connection对象
cursor方法:获取操作数据库的Cursor对象,属于Connection对象
execute方法:用于执行SQL语句,属于Cursor对象
commit方法:在修改数据库后,需要调用该方法提交对数据库的修改,属于Cursor对象
rollback方法:如果修改数据库失败,可以调用该方法进行数据库回滚
'''
from pymysql import *
import json
# 请确保MySQL服务已开启
def connectDB():
Password = input('请输入MySQL账号密码:')
db = connect(host='127.0.0.1',user='root',password=Password,database='test',charset='utf8')
return db
db = connectDB()
# 创建persons表
def createTable(db):
cursor = db.cursor()
sql = '''CREATE TABLE persons
(id INT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
age INT NOT NULL,
address CHAR(50),
salary REAL);'''
try:
cursor.execute(sql)
db.commit()
return True
except:
db.rollback()
return False
# 向persons表插入4条记录
def insertRecords(db):
c = db.cursor()
try:
c.execute('delete from persons')
c.execute("insert into persons(id,name,age,address,salary)\
values(1,'Bill',32,'California',20000.50)")
c.execute("insert into persons(id,name,age,address,salary)\
values(2,'Mary',26,'Texas',1234)")
c.execute("insert into persons(id,name,age,address,salary)\
values(3,'Harry',29,'Norway',5865)")
c.execute("insert into persons(id,name,age,address,salary)\
values(4,'John',30,'Vegas',8353)")
db.commit()
return True
except:
db.rollback()
return False
def selectRecords(db):
cursor = db.cursor()
sql = 'select name,age,address,salary from persons order by age'
cursor.execute(sql)
results = cursor.fetchall()
print(results)
fields = {'name', 'age', 'salary'}
records = []
for row in results:
records.append(dict(zip(fields,row)))
return json.dumps(records)
if createTable(db):
print('成功创建persons表')
else:
print('persons表已经存在')
if insertRecords(db):
print('成功插入记录')
else:
print('插入记录失败')
print(selectRecords(db))
db.close()
请输入MySQL账号密码:12345678
persons表已经存在
成功插入记录
(('Mary', 26, 'Texas', 1234.0), ('Harry', 29, 'Norway', 5865.0), ('John', 30, 'Vegas', 8353.0), ('Bill', 32, 'California', 20000.5))
[{"age": "Mary", "name": 26, "salary": "Texas"}, {"age": "Harry", "name": 29, "salary": "Norway"}, {"age": "John", "name": 30, "salary": "Vegas"}, {"age": "Bill", "name": 32, "salary": "California"}]
'''
ORM:Object Relational Mapping抽象SQL,或者说将SQL语句直接映射成python对象
SQLAlchemy,SQLObject
'''
from sqlalchemy import create_engine,MetaData,Table,Column,Integer,String,Float,exc,orm
from sqlalchemy.ext.declarative import declarative_base
mysql = 'mysql+pymysql://root:12345678@localhost:3306/test?charset=utf8'
# 需要在本地先创建一个名为test的数据库(安装MySQL时可以同时安装workbench,使用workbench进行数据库操作)
tableName = 'persons1'
engine = create_engine(mysql,encoding='utf-8')
# 连接MySQL数据库
engine.connect()
metadata = MetaData(engine)
person = Table(tableName,metadata,
Column('id',Integer,primary_key=True),
Column('name',String(30)),
Column('age',Integer),
Column('address',String(100)),
Column('salary',Float))
metadata.create_all(engine)
Base = declarative_base()
class Person(Base):
__tablename__ = tableName
id = Column(Integer,primary_key= True)
name = Column(String(30))
age = Column(Integer)
address = Column(String(100))
salary = Column(Float)
Session = orm.sessionmaker(bind = engine)
session = Session()
# 先删除persons1表中的所有记录
session.query(Person).delete()
session.commit()
# 插入新的记录
person1 = Person(id = 10,name='Bill',age=30,address='地球',salary=30000)
person2 = Person(id =20,name='Mike',age=34,address='火星',salary=8978)
person3 = Person(id=30, name='John',age=24,address='月球',salary=7865)
session.add(person1)
session.add(person2)
session.add(person3)
session.commit()
print('成功插入记录')
# 使用query进行条件查询
session.query(Person).filter(Person.name=='Mike').update({'address':'千星之城'})
query = session.query(Person).filter(Person.name=='John')
print(query)
person = query.scalar() # 调用scalar函数,要确保query的查询结果只有一条,否则会报错
print(person.name)
# 修改数据库记录
person.age = 55
person.salary = 5646
session.commit()
print('成功更新记录')
# 使用组合条件查询persons1表中的记录
persons = session.query(Person).filter((Person.age>=10)&(Person.salary>=2000))
for person in persons:
print('name =',person.name,end=' ')
print('age =',person.age,end=' ')
print()
print(persons.first().name)
print(persons.offset(2).scalar().name) # offset(2)隐藏掉persons中的前两个对象,仅剩最后一个对象
session.delete(person2)
session.commit()
session.close()
成功插入记录
SELECT persons1.id AS persons1_id, persons1.name AS persons1_name, persons1.age AS persons1_age, persons1.address AS persons1_address, persons1.salary AS persons1_salary
FROM persons1
WHERE persons1.name = %(name_1)s
John
成功更新记录
name = Bill age = 30
name = Mike age = 34
name = John age = 55
Bill
John
'''
使用SQLObject不需要调用commit就能对数据库进行操作
'''
from sqlobject import *
from sqlobject.mysql import builder
mysql = 'mysql://root:12345678@localhost:3306/test?charset=utf8'
sqlhub.processConnection = connectionForURI(mysql,driver='pymysql')
class Person(SQLObject):
class sqlmeta:
table = 'persons'
name = StringCol(length = 30)
age = IntCol()
address = StringCol(length = 30)
salary = FloatCol()
try:
Person.dropTable() # 删除persons表
except:
pass
Person.createTable() # 重新创建persons表
print('成功创建persons表')
person1 = Person(name='Bill',age=30,address='地球',salary=30000)
person2 = Person(name='Mike',age=34,address='火星',salary=8978)
person3 = Person(name='John',age=24,address='月球',salary=7865)
person2.name='李宁'
person2.address = '月球'
persons = Person.selectBy(name='Bill')
print(type(persons))
print(persons[0])
print(persons.count())
print(persons[0].id,persons[0].name,persons[0].address,persons[0].salary,end=' ')
def person2Dict(obj):
return {
'id':obj.id,
'name':obj.name,
'address':obj.address,
'salary':obj.salary
}
import json
jsonStr = json.dumps(persons[0],default=person2Dict,ensure_ascii=False)
print(jsonStr)
persons[0].destroySelf()
成功创建persons表
<class 'sqlobject.sresults.SelectResults'>
<Person 1 name='Bill' age=30 address='地球' salary=30000.0>
1
1 Bill 地球 30000.0 {"id": 1, "name": "Bill", "address": "地球", "salary": 30000.0}
'''
关系型数据库:SQLite、MySQL
关系型数据库将数据保存到二维表中
NoSQL类型:对象数据库、键值数据库、文档数据库、图形数据库、表格数据库
MongoDB:文档数据库 https://www.mongodb.com/try/download/community
MongoDB图形界面 https://www.mongodb.com/try/download/compass
'''
# 使用MongoDB可以将博文t_blogs与博文下的评论t_comments都保存到一个文档中
from pymongo import *
# 命令行窗口调用mongod打开MongoDB服务,然后连接MongoDB数据库
Client = MongoClient()
# 打开或创建名为hello的collection,collection相当于关系型数据库中的数据库
db = Client.hello
person1 = {'name':'Bill','age':27,"address":'地球','salary':8435}
person2 = {'name':'Mary','age':23,"address":'火星','salary':3446}
# 创建或打开一个名为persons的文档,persons相当于关系型数据库中的表
persons = db.persons
# $gt > $lt <
persons.delete_many({'age':{'$gt':0}})
personId1 = persons.insert_one(person1).inserted_id
personId2 = persons.insert_one(person2).inserted_id
print(personId2)
'''
personList = [person1, person2]
result = persons.insert_many(personList)
print(result.inserted_ids)
'''
print(persons.find_one()) # 查找输入的第一个文档
print(persons.find_one()['name'])
# 搜索所有的数据
for person in persons.find():
print(person)
print('---------------------------------')
# 更新数据
persons.update_one({'age':{'$lt':25}},{'$set':{'name':'超人'}})
for person in persons.find():
print(person)
print('------------------------------')
# 删除数据
persons.delete_one({'age':{'$gt':25}})
for person in persons.find({'age':{'$lt':30}}):
print(person)
print('总数 = ',persons.estimated_document_count())
618e2050fc9bc01d8090efb0
{'_id': ObjectId('618e2050fc9bc01d8090efaf'), 'name': 'Bill', 'age': 27, 'address': '地球', 'salary': 8435}
Bill
{'_id': ObjectId('618e2050fc9bc01d8090efaf'), 'name': 'Bill', 'age': 27, 'address': '地球', 'salary': 8435}
{'_id': ObjectId('618e2050fc9bc01d8090efb0'), 'name': 'Mary', 'age': 23, 'address': '火星', 'salary': 3446}
---------------------------------
{'_id': ObjectId('618e2050fc9bc01d8090efaf'), 'name': 'Bill', 'age': 27, 'address': '地球', 'salary': 8435}
{'_id': ObjectId('618e2050fc9bc01d8090efb0'), 'name': '超人', 'age': 23, 'address': '火星', 'salary': 3446}
------------------------------
{'_id': ObjectId('618e2050fc9bc01d8090efb0'), 'name': '超人', 'age': 23, 'address': '火星', 'salary': 3446}
总数 = 1
'''
TCP:传输控制协议,面向连接的,保证数据的可达性
UDP:数据报协议,无连接的,不保证数据一定可以到达另一端
'''
# 建立TCP服务端
from socket import *
host = ''
bufferSize = 1024
port = 9876
addr = (host, port)
# 1、创建Socket对象
# AF_INET: IPV4 AF_INET6:IPV6 SOCK_STREAM:TCP
tcpServerSocket = socket(AF_INET, SOCK_STREAM)
# 2、绑定一个端口号
tcpServerSocket.bind(addr)
# 3、监听端口号
tcpServerSocket.listen()
# 4、等待客户端Socket的连接
print('Server port:9876')
print('正在等待客户端连接')
tcpClientSocket, addr = tcpServerSocket.accept()
print('客户端已经连接','address =',addr)
# 5、读取从客户端发过来的数据
data = tcpClientSocket.recv(bufferSize) # 最多读取bufferSize个字节的数据
print(data.decode('utf8'))
# 6、向客户端发送数据
tcpClientSocket.send('你好 I love you.\n'.encode(encoding='gbk')) # windows系统的cmd窗口默认使用gbk编码
# 7、关闭客户端的Socket连接
tcpClientSocket.close()
# 8、关闭服务端的Socket连接
tcpServerSocket.close()
'''
windows系统需要配置Telnet客户端 https://jingyan.baidu.com/article/ca00d56c186d40e99febcf62.html
运行本程序后,打开cmd命令行窗口,输入:telnet localhost 9876
连接成功后,键盘输入:Ctrl + ]
再输入send+要传输的信息,如:send hello world
'''
Server port:9876
正在等待客户端连接
客户端已经连接 address = ('127.0.0.1', 54741)
hello world
'''
如果客户端发送给服务器的数据过多,需要分多次读取,每次最多读取缓冲区尺寸的数据,bufferSize
'''
from socket import *
host = ''
bufferSize = 2
port = 9876
addr = (host, port)
tcpServerSocket = socket(AF_INET, SOCK_STREAM)
tcpServerSocket.bind(addr)
tcpServerSocket.listen()
print('Server port:9876')
print('正在等待客户端连接')
tcpClientSocket, addr = tcpServerSocket.accept()
print('客户端已经连接','addr =',addr)
fullDataBytes = b''
while True:
# 每次最多读取两个字节的数据
data = tcpClientSocket.recv(bufferSize)
print(data) # 打印出来可以清晰看到每次只读取了两个字节
fullDataBytes += data
if len(data) < bufferSize:
break
print(fullDataBytes)
print(fullDataBytes.decode('ISO-8859-1'))
tcpClientSocket.close()
tcpServerSocket.close()
Server port:9876
正在等待客户端连接
客户端已经连接 addr = ('127.0.0.1', 54773)
b'he'
b'll'
b'o '
b'wo'
b'rl'
b'd'
b'hello world'
hello world
'''
请求队列根据操作系统的不同,存储客户端Socket是有上限的,Linux:128
'''
from socket import *
host = ''
bufferSize = 1024
port = 9876
addr = (host, port)
tcpServerSocket = socket(AF_INET, SOCK_STREAM)
tcpServerSocket.bind(addr)
tcpServerSocket.listen(2)
print('Server port:9876')
print('正在等待客户端连接')
while True:
tcpClientSocket, addr = tcpServerSocket.accept()
print('客户端已经连接', 'addr =', addr)
data = tcpClientSocket.recv(bufferSize)
print(data.decode('utf8'))
tcpClientSocket.send('你好 I love you.\n'.encode(encoding='gbk'))
tcpClientSocket.close()
tcpServerSocket.close()
Server port:9876
正在等待客户端连接
客户端已经连接 addr = ('127.0.0.1', 54821)
hello world1
客户端已经连接 addr = ('127.0.0.1', 54830)
hello world2
客户端已经连接 addr = ('127.0.0.1', 54856)
hello world3
客户端已经连接 addr = ('127.0.0.1', 54891)
hello world4
# 先运行本程序,再运行demo15.6.py
from socket import *
from time import ctime
host = ''
bufferSize = 1024
port = 1234
addr = (host, port)
tcpServerSocket = socket(AF_INET, SOCK_STREAM)
tcpServerSocket.bind(addr)
tcpServerSocket.listen()
while True:
print('正在等待客户端连接')
tcpClientSocket, addr = tcpServerSocket.accept()
print('客户端已经连接', 'addr =', addr)
while True:
data = tcpClientSocket.recv(bufferSize)
if not data:
break
tcpClientSocket.send(ctime().encode(encoding='utf-8')+ b' '+data)
tcpClientSocket.close()
tcpServerSocket.close()
正在等待客户端连接
客户端已经连接 addr = ('127.0.0.1', 54938)
'''
HTTP请求头
HTTP响应头
Chrome浏览器,右键-检查,选择network,刷新页面,出现一个文件,点击,就能查看HTTP请求头与响应头
'''
# 运行本程序后,打开浏览器,输入localhost:8765/test.txt、localhost:8765/index.html、或随便的后缀地址localhost:8765/asklgyhag
# 还可以使用浏览器查看上述地址的HTTP请求头和响应头
from socket import *
import os
# 从文件中读取要返回的HTTP响应头文本,并将设置返回数据长度为length
def responseHeaders(file, length):
f = open(file, 'r')
headersText = f.read()
headersText = headersText % length # 文本中有占位符'%d',这里会由参数length进行替换
return headersText
print(responseHeaders('response_headers.txt', 10))
# 根据HTTP请求头的路径得到服务端的本地路径
def filePath(get):
if get == '/':
return 'static'+os.sep+'index.html'
else:
paths = get.split('/')
s = 'static'
for path in paths:
if path.strip() != '':
s = s + os.sep + path
return s
host = ''
bufferSize = 1024
port = 8765
addr = (host, port)
tcpServerSocker = socket(AF_INET, SOCK_STREAM)
tcpServerSocker.bind(addr)
tcpServerSocker.listen()
while True:
print('正在等待客户端连接...')
tcpClientSocket, addr = tcpServerSocker.accept()
print('客户端已经连接','addr =',addr)
data = tcpClientSocket.recv(bufferSize)
data = data.decode('utf-8')
try:
# 获取HTTP请求头的第一行
firstLine = data.split('\n')[0]
# 获取请求路径
path = firstLine.split(' ')[1]
# 将Web路径转换为本地路径
path = filePath(path)
if os.path.exists(path):
file = open(path, 'rb')
content = file.read()
file.close()
else:
content = 'File Not Found
'.encode(encoding='utf-8')
rh = responseHeaders('response_headers.txt',len(content)) +'\r\n'
tcpClientSocket.send(rh.encode(encoding='utf-8')+content)
except Exception as e:
print(e)
tcpClientSocket.close()
tcpServerSocket.close()
HTTP/1.1 200 OK
Server:custom
Content-Type:text/html
Content-length:10
正在等待客户端连接...
客户端已经连接 addr = ('127.0.0.1', 55041)
正在等待客户端连接...
# 先运行demo15.4.py,再运行本程序
from socket import *
host = 'localhost'
port = 1234
bufferSize = 1024
addr = (host, port)
tcpClientSocket = socket(AF_INET, SOCK_STREAM)
tcpClientSocket.connect(addr)
while True:
data = input('>')
if not data:
break
data = data.encode(encoding='utf-8')
tcpClientSocket.send(data)
data = tcpClientSocket.recv(bufferSize)
print(data.decode('utf-8'))
tcpClientSocket.close()
>hello world
Sat Nov 13 15:28:22 2021 hello world
>there you are
Sat Nov 13 15:28:33 2021 there you are
>
# 结合demo15.8.py
from socket import *
from time import ctime
host = ''
port = 9876
bufferSize = 1024
addr = (host, port)
udpServerSocket = socket(AF_INET, SOCK_DGRAM)
udpServerSocket.bind(addr)
while True:
print('正在等待消息......')
data,addr = udpServerSocket.recvfrom(bufferSize)
udpServerSocket.sendto(ctime().encode(encoding='utf-8')+b' ',addr)
print('客户端地址:',addr)
udpServerSocket.close()
正在等待消息......
客户端地址: ('127.0.0.1', 61648)
正在等待消息......
客户端地址: ('127.0.0.1', 61648)
正在等待消息......
from socket import *
host = 'localhost'
port = 9876
bufferSize = 1024
addr = (host, port)
udpClientSocket = socket(AF_INET, SOCK_DGRAM)
while True:
data = input('>')
if not data:
break
data = data.encode(encoding='utf-8')
udpClientSocket.sendto(data,addr)
data,addr = udpClientSocket.recvfrom(bufferSize)
if not data:
break
print(data.decode('utf-8'))
udpClientSocket.close()
>hi,there
Sat Nov 13 15:38:35 2021
>how are you
Sat Nov 13 15:38:40 2021
>
from socketserver import (TCPServer as TCP, StreamRequestHandler as SRH)
from time import ctime
host = ''
port = 9876
addr = (host, port)
class MyRequestHandler(SRH):
def handle(self):
print('客户端已经连接,地址:',self.client_address)
self.wfile.write(ctime().encode(encoding='utf-8')+b''+self.rfile.readline())
tcpServer = TCP(addr, MyRequestHandler)
tcpServer.serve_forever()
客户端已经连接,地址: ('127.0.0.1', 55413)
说明:本章的多个代码使用的是同一个端口,运行时可能出现端口占用的情况,可以通过查看和关闭本地端口解决。
https://www.cnblogs.com/bulrush/p/11120214.html
'''
1. urllib3
2. Twisted
3. FTP
4. Email
'''
from urllib3 import *
from urllib.parse import urlencode
disable_warnings()
http = PoolManager()
url = 'http://www.baidu.com/s?' + urlencode({'wd':'极客起源'})
print(url)
response = http.request('GET', url)
print(response.data.decode('utf-8'))
# 返回未经渲染的html格式的搜索内容
http://www.baidu.com/s?wd=%E6%9E%81%E5%AE%A2%E8%B5%B7%E6%BA%90
# 检索返回内容过长,这里不作展示
# 先运行server.py,再运行本程序
from urllib3 import *
disable_warnings()
http = PoolManager()
url = 'http://localhost:5000/register'
response = http.request('POST', url, fields={'name':'李宁','age':30})
data = response.data.decode('utf-8')
print(data)
注册成功
server.py
from flask import Flask,request
app = Flask(__name__)
@app.route('/register',methods = ['POST'])
def register():
print(request.form.get('name'))
print(request.form.get('age'))
return '注册成功'
if __name__ == '__main__':
app.run()
* Serving Flask app 'server' (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [13/Nov/2021 16:11:32] "POST /register HTTP/1.1" 200 -
李宁
30
# 利用Google浏览器对网页的右键-检查功能,查看一个网页的HTTP请求头、响应头格式
from urllib3 import *
import re
disable_warnings()
http = PoolManager()
url = 'https://list.tmall.com/search_product.htm?q=%E7%94%B5%E8%84%91&type=p&vmarket=&spm=875.7931836%2FB.a2227oh.d100&from=mallfp..pc_1_searchbutton'
def str2Headers(file):
headerDict={}
f = open(file,'r')
headersText = f.read()
headers = re.split('\n',headersText)
for header in headers:
result = re.split(':',header,maxsplit=1)
headerDict[result[0]] = result[1]
f.close()
return headerDict
headers = str2Headers('header.txt')
# print(headers)
response = http.request('GET',url,headers = headers)
data = response.data.decode('GB18030')
print(data)
from urllib3 import *
disable_warnings()
http=PoolManager()
url = 'https://www.baidu.com'
response=http.request('GET',url)
print(response.info())
print()
print(response.info()['content-Length'])
HTTPHeaderDict({'Accept-Ranges': 'bytes', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Length': '227', 'Content-Type': 'text/html', 'Date': 'Sat, 13 Nov 2021 08:30:24 GMT', 'P3p': 'CP=" OTI DSP COR IVA OUR IND COM ", CP=" OTI DSP COR IVA OUR IND COM "', 'Pragma': 'no-cache', 'Server': 'BWS/1.1', 'Set-Cookie': 'BD_NOT_HTTPS=1; path=/; Max-Age=300, BIDUPSID=197EA2480ADF71253F42D4DE3B72745A; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com, PSTM=1636792224; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com, BAIDUID=197EA2480ADF7125CE4A18C488A5908E:FG=1; max-age=31536000; expires=Sun, 13-Nov-22 08:30:24 GMT; domain=.baidu.com; path=/; version=1; comment=bd', 'Strict-Transport-Security': 'max-age=0', 'Traceid': '1636792224085861863410111604001318584065', 'X-Frame-Options': 'sameorigin', 'X-Ua-Compatible': 'IE=Edge,chrome=1'})
227
# 先运行upload_server.py
from urllib3 import *
disable_warnings()
http = PoolManager()
url='http://localhost:5000'
while True:
filename=input('请输入要上传的文件名:')
if not filename:
break
with open(filename,'rb') as f:
fileData = f.read()
response = http.request('POST',url,fields={'file':(filename,fileData)})
print(response.data.decode('utf-8'))
upload_server.py
import os
from flask import Flask,request
UPDATE_FOLDER='uploads'
app=Flask(__name__)
@app.route('/',methods=['POST'])
def upload_file():
file = request.files['file']
if file:
file.save(os.path.join(UPDATE_FOLDER,file.filename))
return '文件上传成功'
if __name__ == '__main__':
app.run()
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [13/Nov/2021 16:47:57] "POST / HTTP/1.1" 200 -
请输入要上传的文件名:header.txt
文件上传成功
'''
urllib3:连接超时、读超时
http.request('GET',url,timeout=Timeout(connect=2.0,read=3.0))
'''
from urllib3 import *
disable_warnings()
http=PoolManager(timeout=Timeout(connect=2.0,read=3.0))
url1='http://www.baidu123.com'
url2='http://httpbin.org/delay/3'
try:
http.request('GET',url1)
except Exception as e:
print(e)
response=http.request('GET',url2,timeout=Timeout(connect=2.0,read=4.0))
print(response.info)
response=http.request('GET',url2,timeout=Timeout(connect=2.0,read=2.0))
'''
Twisted是一个完整的事件驱动的网络框架(异步编程模型的网络框架),scrapy底层使用了Twisted
1、同步编程模型:一个任务执行完成才执行下一个任务
2、线程编程模型:多个任务同时开始执行
3、异步编程模型:按同步方式执行多个任务,但是当某个任务暂停,会先执行另一个任务
为什么要使用异步编程模型?
1、线程编程模型使用起来很复杂,而且由于线程调度不可控,所以在使用线程模型时要认为这些线程是同时执行的(尽管实际情况并非如此),因此要在代码上加一些与线程有关的机制,如同步、加锁、解锁等
2、如果有一两个任务需要与用户交互,使用异步编程可以立刻切换到其他任务,这一切是可控的
3、任务之间相互独立,以至于任务内部的交互很少,异步编程比线程编程更简单、更易操作
'''
'''
Reactor(反应堆)模型
demo:
使用Socket来访问多个服务器
select模块中的select方法监视所有的socket是否有数据需要接受
1、Twisted的Reactor模式必须通过run函数启动
2、run函数需要在主线程中运行
3、一旦启动Reactor,会一直运行下去。Reactor会在程序控制之下
4、Reactor循环不会消耗任何的CPU资源
'''
# 注意:pollreactor需要从select模块中导入poll等类,而在Windows下,select模块的使用受限
# Note that on Windows, it only works for sockets; on other operating systems, it also works for other file types (in particular, on Unix, it works on pipes).
# 该程序无法在Windows下运行
from twisted.internet import pollreactor
pollreactor.install()
def hello():
print('Hello, how are you?')
from twisted.internet import reactor
reactor.callWhenRunning(hello)
reactor.run()
'''
connectedTCP函数、host、port、ClientFactory
'''
# 先运行demo15.4.py,再运行本程序
from twisted.internet import protocol,reactor
host = 'localhost'
port = 1234
class MyProtocol(protocol.Protocol):
def sendData(self):
data = input('>')
if data:
print('...正在发送 %s' % data)
self.transport.write(data.encode(encoding='utf-8'))
else:
self.transport.loseConnection()
# 发送数据
def connectionMade(self):
self.sendData()
def dataReceived(self, data):
print(data.decode('utf-8'))
self.sendData()
class MyFactory(protocol.ClientFactory):
protocol = MyProtocol
clientConnetionLost = clientConnectionFailed = lambda self,connector,reason:reactor.stop()
reactor.connectTCP(host,port,MyFactory())
reactor.run()
>hello world
...正在发送 hello world
Tue Nov 16 12:11:08 2021 hello world
>
# 运行本程序后,再运行demo16.8.py启动客户端
from twisted.internet import protocol,reactor
from time import ctime
port=1234
class MyProtocol(protocol.Protocol):
def connectionMade(self):
# 获取客户端的IP
client = self.transport.getPeer().host
print(f"客户端{client}已经连接")
def dataReceived(self, data):
self.transport.write(ctime().encode(encoding='utf-8'))
factory = protocol.Factory()
factory.protocol=MyProtocol
print('正在等待客户端的连接......')
reactor.listenTCP(port,factory)
reactor.run()
正在等待客户端的连接......
客户端127.0.0.1已经连接
'''
Mac OS X 启动FTP服务器
sudo -s launchctl load -w /System/Library/LaunchDaemons/ftp.plist
关闭:sudo -s launchctl unload -w /System/Library/LaunchDaemons/ftp.plist
Windows系统:需要开启FTP服务 https://www.cnblogs.com/ziyu-trip/p/7844162.html
'''
'''
1、login(username,password):登录FTP服务器
2、cwd(dirname):改变当前目录
3、dir(callback):列出当前目录中所有的子目录和文件
4、mkd(dirname):当前目录下建立子目录
5、storlines(cmd,f):向FTP服务器上传文本文件,cmd是FTP命令,如STOR filenam
f是文件对象,要用文本方式打开,如f=open(filename,'r')
6、storbinary(cmd,f):向FTP服务器上传二进制文件
7、retrlines(cmd,f):从FTP服务器下载文本文件
8、retrbinary(cmd,f):从FTP服务器下载二进制文件
9、quit():关闭FTP连接并退出
'''
import ftplib
host='192.168.1.8' # windows系统下,host修改为本机IP
# def dirCallback(dir):
# print("hi",dir) # 自定义目录打印格式,可以取消注释对比查看效果
def main():
try:
f=ftplib.FTP(host)
f.encoding='gbk'
# Windows系统下,ftplib默认使用utf-8编码,使用dir()时,如果目录中的文件名包含中文,会报错UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb7 in position 93: invalid start byte
# 经测试,需要添加上面这行代码,f.encoding='gbk'或'gb2312'或'gb18030',可以正常读取中文名的文件
except Exception as e:
print(e)
return
print('FTP服务器已经连接成功')
try:
f.login('localhost','12345678')
except Exception as e:
print(e)
return
print('FTP服务器已经登录成功')
f.cwd('Pictures') # 'Pictures'改为本机FTP根目录下的目录名
f.dir() # 可以添加回调函数dirCallback作为参数,即f.dir(dirCallback)
print('当前的工作目录',f.pwd())
main()
FTP服务器已经连接成功
FTP服务器已经登录成功
11-14-21 09:56PM 0 test1.txt
11-14-21 09:56PM 0 test符-.txt
11-15-21 12:15PM <DIR> Videos
当前的工作目录 /Pictures
'''
SMTP:Simple Message Transfer
[email protected](smtp.126.com) [email protected](stmp.sina.com)
email -> smtp.126.com -> stmp.sina.com -> pop3.sina.com/imap4.sina.com -> 送达
内置的smtplib模块
1、创建SMTP或SMTP_SSL对象
2、登录Email
3、准备MIMEText对象
4、发送Email
'''
import smtplib
from email.mime.text import MIMEText
sender = input("发送人的邮箱账号,如[email protected]:")
password = input('发送人的邮箱密码(使用qq邮箱发送时,需要输入授权码而非邮箱密码):')
to = input('收件人的邮箱账号,如[email protected]:')
def main():
# 指定邮件正文
msg = MIMEText('这是第一封邮件','plain','utf-8')
msg['From'] = sender
msg['To'] = to
# 设置邮件标题
msg['Subject']= '这是宁哥教育发送的一封email'
# 这里要相应地修改为发送人邮箱的stmp地址,使用qq邮箱发送时需要授权码
server = smtplib.SMTP_SSL('smtp.qq.com',465)
server.login(sender,password)
server.sendmail(sender,[to],msg.as_string())
server.quit()
main()
import smtplib
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
sender = input("发送人的邮箱账号,如[email protected]:")
password = input('发送人的邮箱密码(使用qq邮箱发送时,需要输入授权码而非邮箱密码):')
to = input('收件人的邮箱账号,如[email protected]:')
def mail():
ret = True
try:
msg=MIMEMultipart('related')
msg['From'] = sender
msg['To'] = to
msg['Subject'] = '宁哥教育(带附件)'
msgAlternative=MIMEMultipart('alternative')
msg.attach(msgAlternative)
mail_msg='''
宁哥教育祝广大学员更上一层楼
图片演示:
'''
msgAlternative.attach(MIMEText(mail_msg,'html','utf-8'))
fp = open('Milky Way.jpeg','rb')
msgImage = MIMEImage(fp.read())
fp.close()
msgImage.add_header('Content-ID','' )
msg.attach(msgImage)
server=smtplib.SMTP_SSL('smtp.qq.com',465)
server.login(sender,password)
server.sendmail(sender,[to],msg.as_string())
server.quit()
except Exception as e:
print(e)
ret = False
return ret
ret = mail()
if ret:
print('邮件发送成功')
else:
print('邮件发送失败')
'''
IMAP : Internet Message Access Protocol, IMAP4
IMAP4 和 IMAP3 的区别:
POP3用于从邮件服务器上下载邮件信息,在本地删除、修改邮件,并不会影响服务器上的邮件
IMAP4是双向的,在本地修改、删除邮件,同时会影响到服务器
'''
import imaplib
import base64
connection=imaplib.IMAP4_SSL('imap.qq.com',993)
username=input('请输入邮箱账号:')
password=input('请输入邮箱密码:')
try:
connection.login(username,password)
except Exception as e:
print(e)
connection.print_log() # 打印登录日志
# 列出所有目录
res,data=connection.list()
print('Response code',data)
res,data=connection.select('INBOX') # 切换到INBOX
print(res, data)
print(data[0]) # 输出邮件数
res, msg_ids = connection.search(None, 'ALL') # 搜索所有的邮件
print(res, msg_ids)
res, msg_data=connection.fetch(data[0],'(UID BODY(TEXT)')
print(msg_data)
connection.logout()
'''
POP: Post Office Protocol POP3
'''
import poplib
import re
host = 'pop.qq.com'
username = input('邮箱地址:')
password = input('邮箱密码:')
pp = poplib.POP3_SSL(host)
pp.set_debuglevel(1)
pp.user(username)
pp.pass_(password)
ret = pp.stat()
# 获取邮件总数
mailCount = ret[0]
print(f"一共 {mailCount} 封邮件")
# 取出前20封邮件的头部信息
for i in range(1, mailCount):
try:
mlist = pp.top(i, 0)
# 输出邮件的头部(列表形式)
print(mlist[1])
# 输出subject
print(mlist[1][7])
if i>20: break
except:
pass
ret = pp.list()
down = pp.retr(1)
charset = ''
for line in down[1]:
result = re.search('charset\s*=\s*"([^\"]*)"',line.decode('iso8859-1'))
if result != None:
charset = result.group(1)
print(charset)
if charset != '':
print(line.decode(charset))
pp.quit()
'''
1、python中的线程
2、高级线程模块
3、线程同步
4、生产者-消费者问题与queue模块
'''
'''
进程:静态和动态,静态(exe、dll),进程是动态执行的程序
线程:线程依赖于进程,一个进程可以有多个线程,一个进程必须至少有一个主线程
'''
from time import sleep, ctime
def fun1():
print('开始运行fun1:',ctime())
sleep(4)
print('fun1运行结束:',ctime())
def fun2():
print('开始运行fun2:',ctime())
sleep(2)
print('fun2运行结束:',ctime())
def main():
print('开始运行时间',ctime())
fun1()
fun2()
print('结束运行时间',ctime())
main()
开始运行时间 Tue Nov 16 12:33:53 2021
开始运行fun1: Tue Nov 16 12:33:53 2021
fun1运行结束: Tue Nov 16 12:33:57 2021
开始运行fun2: Tue Nov 16 12:33:57 2021
fun2运行结束: Tue Nov 16 12:33:59 2021
结束运行时间 Tue Nov 16 12:33:59 2021
import _thread as thread
from time import sleep, ctime
def fun1():
print('开始运行fun1:',ctime())
sleep(4)
print('fun1运行结束:',ctime())
def fun2():
print('开始运行fun2:',ctime())
sleep(2)
print('fun2运行结束:',ctime())
def main():
print('开始运行时间',ctime())
thread.start_new_thread(fun1,())
thread.start_new_thread(fun2,())
sleep(6)
print('结束运行时间',ctime())
main()
# 多线程同时开始运行,print语句没有执行完毕就插入了另一个print语句的内容
开始运行时间 Tue Nov 16 12:34:25 2021
开始运行fun1:开始运行fun2: Tue Nov 16 12:34:25 2021Tue Nov 16 12:34:25 2021
fun2运行结束: Tue Nov 16 12:34:27 2021
fun1运行结束: Tue Nov 16 12:34:29 2021
结束运行时间 Tue Nov 16 12:34:31 2021
import random
from time import sleep
import _thread as thread
def fun(a,b):
print(a, b)
sleep(random.randint(1,5))
for i in range(8):
thread.start_new_thread(fun,(i+1,'a'*(i+1)))
input()
# 多线程同时开始运行,print语句没有执行完毕就插入了另一个print语句的内容
2 3aa
aaa
4 aaaa
5 1aaaaa
a6
aaaaaa7
aaaaaaa
8 aaaaaaaa
# 用来检测某个线程是否结束
import _thread as thread
from time import sleep,ctime
def fun(index, sec, lock):
print(F'开始执行 {index} 执行时间:',ctime())
sleep(sec)
print(f"执行结束 {index} 执行时间:",ctime())
lock.release()
lock1 = thread.allocate_lock()
lock1.acquire() # 把锁锁上
thread.start_new_thread(fun,(10,4,lock1))
lock2 = thread.allocate_lock()
lock2.acquire()
thread.start_new_thread(fun,(20,2,lock2))
while lock1.locked() or lock2.locked():
pass
# 当两个线程都没有被锁住时,整个程序执行完毕
# 多线程同时开始运行,print语句没有执行完毕就插入了另一个print语句的内容
开始执行 10 执行时间: 开始执行 20 执行时间:Tue Nov 16 12:36:53 2021
Tue Nov 16 12:36:53 2021
执行结束 20 执行时间: Tue Nov 16 12:36:55 2021
执行结束 10 执行时间: Tue Nov 16 12:36:57 2021
import threading
from time import sleep,ctime
def fun(index,sec):
print(f"开始执行 {index} 时间:",ctime())
sleep(sec)
print(f"结束执行 {index} 时间:",ctime())
thread1 = threading.Thread(target=fun,args=(10,4))
thread1.start()
thread2 = threading.Thread(target=fun,args=(20,2))
thread2.start()
thread1.join()
thread2.join()
print('程序退出')
开始执行 10 时间: Tue Nov 16 12:37:23 2021
开始执行 20 时间: Tue Nov 16 12:37:23 2021
结束执行 20 时间: Tue Nov 16 12:37:25 2021
结束执行 10 时间: Tue Nov 16 12:37:27 2021
程序退出
import threading
from time import sleep,ctime
# 线程类
class MyThread(threading.Thread):
def __init__(self,func,args,name=''):
super().__init__(target=func,name=name,args=args)
def run(self):
self._target(*self._args) # 内部变量
# 线程函数
def fun(index, sec):
print(f"开始执行 {index} 时间:{ctime()}")
sleep(sec)
print(f"执行完毕 {index} 时间:{ctime()}")
print('开始:',ctime())
thread1 = MyThread(fun,(10,4),'线程1')
thread2 = MyThread(fun,(20,2),'线程2')
thread1.start()
thread2.start()
print(thread1.name)
print(thread2.name)
thread1.join()
thread2.join()
print('结束:',ctime())
开始: Tue Nov 16 12:37:45 2021
开始执行 10 时间:Tue Nov 16 12:37:45 2021
开始执行 20 时间:Tue Nov 16 12:37:45 2021线程1
线程2
执行完毕 20 时间:Tue Nov 16 12:37:47 2021
执行完毕 10 时间:Tue Nov 16 12:37:49 2021
结束: Tue Nov 16 12:37:49 2021
import random
from time import sleep,ctime
from threading import Thread,Lock,current_thread
from atexit import register
# 创建线程锁对象
lock = Lock()
def fun():
# 获取线程锁权限
lock.acquire()
# 将for循环变成原子操作
for i in range(5):
print('Thread Name =',current_thread().name,'i=',i)
sleep(random.randint(1,5))
lock.release()
def main():
for i in range(3):
Thread(target=fun).start()
@register
def exit():
print('线程执行完毕',ctime())
main()
Thread Name = Thread-1 (fun) i= 0
Thread Name = Thread-1 (fun) i= 1
Thread Name = Thread-1 (fun) i= 2
Thread Name = Thread-1 (fun) i= 3
Thread Name = Thread-1 (fun) i= 4
Thread Name = Thread-2 (fun) i= 0
Thread Name = Thread-2 (fun) i= 1
Thread Name = Thread-2 (fun) i= 2
Thread Name = Thread-2 (fun) i= 3
Thread Name = Thread-2 (fun) i= 4
Thread Name = Thread-3 (fun) i= 0
Thread Name = Thread-3 (fun) i= 1
Thread Name = Thread-3 (fun) i= 2
Thread Name = Thread-3 (fun) i= 3
Thread Name = Thread-3 (fun) i= 4
线程执行完毕 Tue Nov 16 12:39:11 2021
'''
信号量是一个计数器 消耗资源:p 释放资源:v
acquire release
'''
from threading import BoundedSemaphore
MAX = 3
semaphore = BoundedSemaphore(MAX)
print(semaphore._value)
# 计数器减1
semaphore.acquire()
print(semaphore._value)
semaphore.acquire()
print(semaphore._value)
semaphore.acquire()
print(semaphore._value)
print(semaphore.acquire(False)) # 此时调用程序会堵塞
# 释放资源
semaphore.release()
print(semaphore._value)
semaphore.release()
print(semaphore._value)
semaphore.release()
print(semaphore._value)
# semaphore.release() # 释放资源超过MAX,会报错
3
2
1
0
False
1
2
3
from random import randrange
from time import sleep,time,ctime
from threading import Lock,Thread
from queue import Queue
lock = Lock()
class MyThread(Thread):
def __init__(self,func,args):
super().__init__(target=func,args=args)
# 向队列中添加商品
def writeQ(queue):
lock.acquire()
print('生产了一个对象,并将其添加到队列中',end=' ')
queue.put('商品')
print('队列尺寸',queue.qsize())
lock.release()
# 从队列中获取商品
def readQ(queue):
lock.acquire()
val = queue.get(1)
print('消费了一个对象,队列尺寸',queue.qsize())
lock.release()
def writer(queue, loops):
for i in range(loops):
writeQ(queue)
sleep(randrange(1,4))
def reader(queue,loops):
for i in range(loops):
readQ(queue)
sleep(randrange(2,6))
funcs=[writer,reader]
nfuncs=range(len(funcs))
def main():
nloops=randrange(2,6)
q=Queue(32)
threads=[]
for i in nfuncs:
t=MyThread(funcs[i],(q,nloops))
threads.append(t)
for i in nfuncs:
threads[i].start()
for i in nfuncs:
threads[i].join()
main()
生产了一个对象,并将其添加到队列中 队列尺寸 1
消费了一个对象,队列尺寸 0
生产了一个对象,并将其添加到队列中 队列尺寸 1
消费了一个对象,队列尺寸 0
生产了一个对象,并将其添加到队列中 队列尺寸 1
消费了一个对象,队列尺寸 0
本章建议自行运行程序,观察图形界面的展示效果。
'''
1、编写第一个tkinter程序
2、布局(pack/place/grid)
3、控件(Label/Button/Text/Radio/Checkbox等)
4、菜单
5、对话框
Python默认的GUI库,基于Tk工具包,为TCL(tool command language)设计的
Tk流行后,被移植到其他语言,Python、Perl、Ruby
'''
'''
1、导入tkinter模块
2、创建Tk类的实例,Tk对象表示一个窗口
3、对窗口进行设置
4、创建空间类的实例,并将控件添加到窗口上
5、调用mainloop函数进入事件循环
'''
import tkinter
window = tkinter.Tk()
window['background'] = 'blue'
w = 300
h = 200
# 获取屏幕的宽度和高度
ws = window.winfo_screenwidth()
hs = window.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
window.title('第一个tkinter应用')
window.geometry('%dx%d+%d+%d' % (w,h,x,y)) # geometry的格式设置就是如此!!!
label = tkinter.Label(window, text='Hello World')
label.pack()
tkinter.mainloop()
'''
三种布局方法:pack/grid/place
pack可以指定相对位置,另外两种需要指定绝对位置
'''
from tkinter import *
window = Tk()
window.title('水平居中')
window.geometry('200x100')
window['background'] = 'blue'
Label(window,text='复仇者联盟',bg='red',fg='white').pack()
Label(window,text='正义联盟',bg='green',fg='black').pack()
Label(window,text='天启星',bg='yellow',fg='blue').pack()
mainloop()
from tkinter import *
window = Tk()
window['background'] = 'blue'
window.geometry('200x100')
w = Label(window,text='复仇者联盟',bg='red',fg='white')
w.pack(fill=X)
w = Label(window,text='超人',bg='green',fg='yellow')
w.pack(fill=X)
w = Label(window,text='保卫地球',bg='yellow',fg='blue')
w.pack(fill=X)
mainloop()
from tkinter import *
window = Tk()
window.title('设置水平外边框')
window['background'] = 'blue'
window.geometry('200x100')
w = Label(window,text='复仇者联盟',bg='red',fg='white')
w.pack(fill=X,padx = 10) # 无论窗口拉得多大,Label的左右外边框宽度都是10个像素
w = Label(window,text='超人',bg='green',fg='yellow')
w.pack(fill=X,padx = 10)
w = Label(window,text='保卫地球',bg='yellow',fg='blue')
w.pack(fill=X,padx = 10)
mainloop()
from tkinter import *
window = Tk()
window.title('设置垂直外边框')
window['background'] = 'blue'
window.geometry('200x100')
w = Label(window,text='复仇者联盟',bg='red',fg='white')
w.pack(fill=X,pady = 10) # 无论窗口拉得多大,Label的上下外边框的宽度都是10个像素
w = Label(window,text='超人',bg='green',fg='yellow')
w.pack(fill=X,pady = 10)
w = Label(window,text='保卫地球',bg='yellow',fg='blue')
w.pack(fill=X,pady = 10)
mainloop()
from tkinter import *
window = Tk()
window.title('设置水平及垂直外边框')
window['background'] = 'blue'
window.geometry('200x100')
w = Label(window,text='复仇者联盟',bg='red',fg='white')
w.pack(fill=X,padx=10,pady = 10) # 无论窗口拉得多大,Label的上下、左右外边框的宽度都是10个像素
w = Label(window,text='超人',bg='green',fg='yellow')
w.pack(fill=X,padx=10,pady = 10)
w = Label(window,text='保卫地球',bg='yellow',fg='blue')
w.pack(fill=X,padx=10,pady = 10)
mainloop()
from tkinter import *
window = Tk()
window.title('设置内边距')
window['background'] = 'blue'
window.geometry('200x200')
w = Label(window,text='复仇者联盟',bg='red',fg='white')
w.pack(fill=X,ipadx=10,ipady=10,padx=10,pady = 10)
w = Label(window,text='超人',bg='green',fg='yellow')
w.pack(fill=X,ipadx=10,ipady=10,padx=10,pady = 10)
w = Label(window,text='保卫地球',bg='yellow',fg='blue')
w.pack(fill=X,ipadx=10,ipady=10,padx=10,pady = 10)
mainloop()
# 从左向右排列,如果将下面的side参数改为RIGHT,则可实现从右向左排列
from tkinter import *
window = Tk()
window.title('水平排列')
window['background'] = 'blue'
window.geometry('200x200')
w = Label(window,text='复仇者联盟',bg='red',fg='white')
w.pack(side=LEFT,padx=10,pady = 10)
w = Label(window,text='超人',bg='green',fg='yellow')
w.pack(side=LEFT,padx=10,pady = 10)
w = Label(window,text='保卫地球',bg='yellow',fg='blue')
w.pack(side=LEFT,padx=10,pady = 10)
mainloop()
import random
from tkinter import *
window = Tk()
window.title('place布局')
window['background'] = 'blue'
window.geometry('180x200+30+30')
languages = ['Python','Swift','C++','Java','Kotlin']
labels = range(5)
for i in labels:
# 随机产生三原色
ct = [random.randrange(256) for x in range(3)]
# 取亮度
brightness = int(round(0.299*ct[0]+0.587*ct[1]+0.144*ct[2]))
# 得到背景色的十六进制形式
ct_hex = '%02x%02x%02x' % tuple(ct)
bg_colour='#'+''.join(ct_hex)
label = Label(window,text=languages[i],fg='White' if brightness<120 else 'Black',
bg=bg_colour)
label.place(x=25,y=30+i*30,width=120,height=25)
mainloop()
from tkinter import *
window = Tk()
window.title('grid布局')
window['background'] = 'blue'
window.geometry('400x150+30+30')
colours = ['red','green','orange','white','yellow','blue']
r = 0
for c in colours:
Label(window,text=c,relief=RIDGE,width=15).grid(row=r,column=0)
Label(window,bg=c,relief=RIDGE,width=15).grid(row=r,column=1)
Label(window,text=c,relief=RIDGE,width=15).grid(row=r,column=2)
r = r+1
mainloop()
import tkinter as tk
window = tk.Tk()
window.title('Label控件和Button控件')
window['background'] = 'blue'
window.geometry('300x200+30+30')
label1=tk.Label(window,text='Hello World',bg='green',
font=('Arial',12))
label1.pack()
var=tk.StringVar()
var.set('I love you.')
label2=tk.Label(window,textvariable=var,fg='blue',
bg='yellow',font=('Arial',12),width=15,height=2)
label2.pack(pady=20)
onHit = False
# 第一个按钮的点击回调函数
def hitMe():
global onHit
if onHit==False:
onHit = True
var.set('世界你好')
else:
onHit = False
var.set('I am fine.')
button1=tk.Button(window,text='点击我',command=hitMe)
button1.pack()
def getLabelText():
print(var.get())
button2=tk.Button(window,text='获取Label控件的文本',command=getLabelText)
button2.pack(pady=20)
window.mainloop()
'''
Entry:只能用于输入单行文本
Text:可以用于输入多行文本,还支持图像、富文本
Entry类:构造方法的show参数设置一个字符,回显字符。如show='*'
'''
import tkinter as tk
window=tk.Tk()
window.title('Entry控件与Text控件')
window['background']='blue'
window.geometry('1920x1800+30+30')
entryVar1=tk.StringVar()
def callback():
# 更新第二个Entry控件中的文本
entryVar2.set(entryVar1.get())
# 将entryVar1与callback关联
entryVar1.trace('w',lambda a,b,c:callback())
# 创建第一个Entry控件
entry1=tk.Entry(window,textvariable=entryVar1,show='*')
entry1.pack(pady=10)
entryVar2=tk.StringVar()
entry2=tk.Entry(window,textvariable=entryVar2)
entry2.pack(pady=10)
# Text控件
text=tk.Text(window)
text.pack(pady=10)
# gif/bmp等,不直接支持JPG、png。要使用PIL进行处理才能插入JPG、PNG
from PIL import Image,ImageTk
# PIL包已经更新为pillow包
png=Image.open('pic.png') # 选取的图片不能太大,否则显示不了
photo1=ImageTk.PhotoImage(png)
# # 在Text控件结尾插入图像
text.image_create(tk.END,image=photo1)
# 进行字体、字号等设置,big只是一个标识,相当于字典,对应的值为后面的font
text.tag_configure('big',font=('Arial',25,'bold'))
text.insert(tk.END,'懵圈','big')
jpg=Image.open('pic.jpg')
photo2=ImageTk.PhotoImage(jpg)
text.image_create(tk.END,image=photo2)
window.mainloop()
# 单选控件
import tkinter as tk
window=tk.Tk()
window.title('Radiobutton控件')
window.geometry('200x200')
window['background']='blue'
var=tk.StringVar()
label=tk.Label(window,bg='yellow',width=20,text='empty')
label.pack()
var.set('选项A')
# 当Radiobutton的选择变化后,会调用该函数
def printSelection():
label.config(text='您已经选择了'+var.get())
r1=tk.Radiobutton(window,text='选项A',variable=var,value='A',command=printSelection)
r1.pack()
r2=tk.Radiobutton(window,text='选项B',variable=var,value='B',command=printSelection)
r2.pack()
r3=tk.Radiobutton(window,text='选项C',variable=var,value='C',command=printSelection)
r3.pack()
window.mainloop()
# 多选控件,通过Checkbutton类构造方法的onvalue参数指定控件选中状态的值
# 通过offvalue参数指定控件未选中状态的值
import tkinter as tk
window=tk.Tk()
window.title('Radiobutton控件')
window.geometry('200x200')
window['background']='blue'
label=tk.Label(window,bg='yellow',width=20,text='empty')
label.pack()
# 当Checkbutton的选择变化后,会调用该函数
def printSelection():
text=''
if var1.get()==1:
text += ' '+c1.cget('text')
if var2.get()==1:
text += ' '+c2.cget('text')
if var3.get()==1:
text += ' '+c3.cget('text')
if var4.get()==1:
text += ' '+c4.cget('text')
label.config(text=text)
var1=tk.IntVar()
var2=tk.IntVar()
var3=tk.IntVar()
var4=tk.IntVar()
c1=tk.Checkbutton(window,text='Python',variable=var1,onvalue=1,offvalue=0,
command=printSelection)
c2=tk.Checkbutton(window,text='C++',variable=var2,onvalue=1,offvalue=0,
command=printSelection)
c3=tk.Checkbutton(window,text='Kotlin',variable=var3,onvalue=1,offvalue=0,
command=printSelection)
c4=tk.Checkbutton(window,text='Swift',variable=var4,onvalue=1,offvalue=0,
command=printSelection)
c1.pack()
c2.pack()
c3.pack()
c4.pack()
window.mainloop()
'''
label:在Scale控件旁边显示的标签文本,水平滑块控件在上方显示,垂直滑块在右侧显示
length:Scale控件的长度
from_:滑块能设置的最小值,也是Scale控件的起始值
to:滑块能设置的最大值,也是Scale控件的结束值
tickinterval:Scale控件刻度的步长
resolution:滑块能滑动的步长
command:指定滑动事件对应的函数
orient:设置Scale控件的类型,HORIZONTAL表示水平控件,VERTICAL表示垂直控件
'''
import tkinter as tk
window=tk.Tk()
window.title('Scale控件')
window.geometry('200x400')
window['background']='blue'
label1=tk.Label(window,bg='yellow',width=20)
label1.pack()
# 水平Scale控件滑块滑动时调用的函数
def printSelection1(v):
label1.config(text='当前值:'+v)
scale1=tk.Scale(window,label='拖我',from_=5,to=11,orient=tk.HORIZONTAL,
length=200,tickinterval=2,resolution=0.01,command=printSelection1)
scale1.pack(pady=10)
label2=tk.Label(window,bg='yellow',width=20)
label2.pack()
# 垂直Scale控件滑块滑动时调用的函数
def printSelection2(v):
label2.config(text='当前值:'+v)
scale2=tk.Scale(window,label='拖我',from_=5,to=11,orient=tk.VERTICAL,
length=200,tickinterval=2,resolution=0.01,command=printSelection2)
scale2.pack(pady=10)
window.mainloop()
import tkinter as tk
window=tk.Tk()
window.title('Listbox控件')
window.geometry('300x400')
window['background']='blue'
var1=tk.StringVar()
label=tk.Label(window,textvariable=var1,bg='yellow',width=20)
label.pack()
var2=tk.StringVar()
var2.set((11,22,33,44))
lb=tk.Listbox(window,listvariable=var2)
def onselect(evt):
w=evt.widget
value=w.get(w.curselection())
var1.set(value)
lb.bind('<>' ,onselect)
lb.pack(pady=20)
lb.selection_set(first=0)
value=lb.get(lb.curselection())
var1.set(value)
list_items=[11111,2222,4444,5555]
for item in list_items:
lb.insert('end',item)
lb.insert(1,'Python')
lb.insert(2,'Kotlin')
lb.insert(3,'Swift')
# lb.delete(2)
window.mainloop()
'''
Menu对象 第一个Menu对象,构造方法需要传入window
'''
import tkinter as tk
window=tk.Tk()
window.title('菜单')
window.geometry('300x400')
label=tk.Label(window,width=20,bg='yellow')
label.pack()
counter=0
def menuClick():
global counter
label.config(text='第'+str(counter)+'次点击')
counter +=1
# 创建根菜单
menubar=tk.Menu(window)
# 创建文件菜单
filemenu=tk.Menu(menubar)
menubar.add_cascade(label='文件',menu=filemenu)
filemenu.add_command(label='新建',command=menuClick)
filemenu.add_command(label='打开',command=menuClick)
filemenu.add_command(label='保存',command=menuClick)
# 在“文件”菜单项下添加带子菜单项的“导入”菜单项
submenu=tk.Menu(filemenu)
filemenu.add_cascade(label='导入',menu=submenu)
submenu.add_command(label='导入文本文件',command=menuClick)
submenu.add_command(label='导入PDF文件',command=menuClick)
# 添加一个分隔条
filemenu.add_separator()
filemenu.add_command(label='退出',command=window.quit)
editmenu=tk.Menu(menubar)
menubar.add_cascade(label='编辑',menu=editmenu)
editmenu.add_command(label='剪切',command=menuClick)
editmenu.add_command(label='复制',command=menuClick)
editmenu.add_command(label='粘贴',command=menuClick)
window.config(menu=menubar)
window.mainloop()