python库相当丰富, 需要时候再去找去查,使用方便
这里只是冰山一角
1、自定义库(模块)
跟C中的#include
一致
python
def add(a,b):
print(a+b)
return a+b
def sum(n):
sum = 0
for i in range(n + 1):
sum += i
print(sum)
# 测试部分代码
sum(3)
add(1,2)
use.py调用sum.py中的函数
python
from sum import add,sum
add(2, 3)
sum(4)
直接运行use.py 会把sum.py中的函数之外的操作也运行,注意运行之前需要把 sum.py保存
1.1 指定函数入口(main函数)
希望sum.py给别人使用 作为一个库的时候 不执行测试部分 代码,只有自己运行的时候 才调用
修改sum.py,把测试代码 放入 if __name__ == '__main__':
python
def add(a,b):
print(a+b)
return a+b
def sum(n):
sum = 0
for i in range(n + 1):
sum += i
print(sum)
if __name__ == '__main__': # 做测试代码(调用者是自己时才执行)
sum(3)
add(1,2)
运行sum.py会执行 测试代码
if __name__ == '__main__'
是 Python 中一个常见的 条件语句,用于检查 当前模块是否作为 主程序执行,还是 被导入到其他模块中
当 Python 解释器执行一个文件时,会将其作为一个模块载入,并为该模块指定一个特殊的名称 __name__
。如果一个模块是 作为主程序执行,那么其 __name__
属性的值就会被设置为 '__main__'
,反之,如果模块是 被导入到其他模块中,那么 __name__
的值就会是 该模块的名称
1.2 模块的定义和使用
my_module.py 定义自己的模块
python
def fn(): #函数对象
print('fn go')
person ={'name':'ivan','age':30} #字典(数据)对象
class Animal: #类对象
name = 'animal'
def eat(self):
print(self.name," can eat")
def breath(this):
print(this.name," can breath")
use2.py 使用模块
python
import my_module # 导入模块
my_module.fn() # 访问模块里的函数对象
import my_module as m # 用m做模块假名(使用简洁)
obj = m.Animal() # 使用模块里的类对象 进行实例化
obj.eat()
from my_module import person # 只导入模块里指定对象(数据)
print(person)
运行结果
2、标准库
只要安装了python就有的,不需要额外安装
Python 标准库 官方文档
2.1 时间
range(2) 表示一个生成器对象,它生成从 0 开始的整数序列,直到 2 之前的所有整数
python
from time import ctime,sleep
from datetime import date
print(date.today()) # 今天日期
def music():
for i in range(2):
print("I was listening to music. %s"%ctime()) # 当前时间,年月日时
sleep(1)
def move():
for i in range(2):
print("I was at the movies! %s" %ctime())
sleep(5) # 睡眠5秒
if __name__ == '__main__':
music()
move()
print("all over %s" %ctime())
运行结果
2.2 文件操作
1、文件名 路径;使用linux命令
python
import os
print(os.system('ls')) #执行Linux系统命令ls
执行Linux系统命令ls,跟直接输入 ls一样的
检测文件,目录
python
if os.path.exists('/etc/passwd'): #检测文件存在否
print('file passwd exits')
print(os.path.isfile('/etc/passwd')) #检测是文件否,而不是文件夹
print(os.path.isdir('/etc')) #检测是目录否
运行结果:
获取目录,路径名,文件名,列举目录下的文件
python
print(os.getcwd()) #获取当前目录
print(os.path.dirname('/etc/passwd')) #获取路径名,即文件上一层所在的路径,可以方便 把文件存在同一个目录下面
print(os.path.basename('/etc/passwd')) #获取文件名
print(os.listdir('/etc')) #列举目录下的文件
运行结果:
创建目录,重命名:
python
os.mkdir("dir") #创建目录(文件夹)
os.rename("hello.py","helloPython.py") #重命名
当前目录名称,子目录名称,子文件名称;遍历目录下所有文件;将多个路径组合后返回
python
#遍历目录下所有文件
for(dirname, subdir, subfile) in os.walk('/home/ashergu/VScodeFiles'): # walk返回(当前目录名称,子目录名称,子文件名称)
print('dirname is %s, subdir is %s, subfile is %s' % (dirname, subdir, subfile))
for f in subfile:
print(os.path.join(dirname, f)) #将多个路径组合后返回
运行结果:
注意,walk dirname会把当前目录 及 当前目录下的子目录 以及 子目录下的子目录 ... 直到没有目录为止 都给返回
2、文件读写
存图片,存数据库相关的信息,从本地读出来,通过网络传输,需要操作文件
python
# 本地的话不需要把路径写全,写文件名就行
fd = open('file') #默认只读打开,在一个文件夹内 只要写名字,fd里面存储了文件对象,文件名不存在报错
# 文件对象的相关的方法(封装好的)
print(fd.read()) #读完文件
fd.close() #关闭文件,虽然会自动退出,但是还是加一下,避免别人操作这个文件,关闭了就访问不了了
读取到了文件里的信息
写打开
python
fd = open('newfile','w') #写打开,(如不存在则创建)
fd.write('overflow\n') #覆盖写入+换行
fd.write('add') #追加写入
覆盖写入,再追加信息
newfile文件内容
追加方式打开
python
fd = open('file','a') #追加方式打开
print(fd.write('append')) #追加其后
追加后文件内容
但是不允许读
python
print(fd.read())
读写打开,位置偏移
python
fd = open('newfile','r+') #读写打开,可以写可以读
print(fd.read(5)) #读5个字符,默认从头读到尾
print(fd.read(5)) #再读5个字符(包括换行符))
print(fd.tell()) #返回文件操作标记的当前位置(之前累积读的位置),以文件的开头为原点
print(fd.seek(2,0)) #设置文件位置 offset:偏移(跳过几个字符) 后面一个参数为跳过的起点位置 where:0从头开始 1当前位置为原点计算 2末尾为原点
print(fd.read(3)) #再读3个字符(接着前面位置往后读,从头开始,跳过了两个位置,从3开始读)
print(fd.read(3)) #再读3个字符(接着前面位置往后读,跳过了两个位置)
fd.write('\ngogo') #先读则从尾部写入,否则从头部开始写入,后面未写到位置数据不变
# print(fd.readline()) #读一行
# 使用 readline() 之前执行完光标在文件末尾了,再读一行 没有数据了,因此返回的是空字符串,表示没有读取到数据
print(fd.seek(2,0))
print(fd.readline()) #读一行
运行结果
二进制读取
python
data_file = 'MNIST_data/train-images-idx3-ubyte.gz'
print(open(data_file, 'rb').read(32)) #rb:二进制读取
运行结果
转回 utf-8,with 会自动释放资源(省去close)
python
with open('data', 'rb') as f: #with 会自动释放资源(省去close),名字是f
data = f.read() # b'' 代表二进制
print(data)
text = data.decode('utf-8') #转换为utf-8字符编码
print(text)
运行结果
3、字节流转换(对二进制文件(如图像 音频)解析)
读二进制文件(mp4)
python
fd = open("mp4_file.mp4",'rb')# 二进制文件读(如 video.mp4 music.mp3 a.out a.bin)
# 二进制读,需加rb,否则默认是以文本字符串utf-8方式读(看成文本文件),会报错
print(fd.read(32)) # 但是二进制太多了,所以打印出来 用16位方式打印出来
print(fd.read(30).decode('utf-8')) # 转换为文本字符串
fd.close()
运行结果:
以读写的方式打开二进制文件
python
fd = open("mp4_file.mp4",'r+b')
name =b'ashergu'
print(fd.read(32))
print(fd.write(name)) # 以二进制打开 不能用传统的文本的方式写,必须要用 二进制方式字符串
fd.close()
运行结果
字典类型的写入和解析,将文件中写入的数据按照格式读取出来
附:struct库
struct模块的核心函数 是pack()和unpack()。pack()函数 将Python数据类型打包成二进制字符串,而unpack()函数则将二进制字符串解析为Python数据类型
python
import struct
fp = open('test.bin','wb') # 文件不存在,会创建
# 按照上面的格式将数据写入文件中
# 这里如果string类型的话,在pack函数中就需要encode('utf-8')
name = b'ashergu'
age = 22 # 数值二进制存储 没有问题,跟字符串不同
sex = b'male'
job = b'engineer'
fp.write(struct.pack('7si4s8s', name,age,sex,job)) # c:char :bool >:大端 <:小端
# b:signed char B:unsigned char
# i:int I:unsigned int f:float
# d:double s:string数字表示有几个字符
fp.flush() # 把缓冲区的内容写入硬盘
fp.close()
# 直接读
fd = open('test.bin','rb')
print(fd.read())
fd.close()
# 将文件中写入的数据按照格式读取出来
fd = open('test.bin','rb')
# 23 = 7 + 4 + 4 + 8
print(struct.unpack('7si4s8s',fd.read(24))) # 23会报错提示要读24个,也不知道为啥,要加1
fd.close()
运行结果
2.3 多线程
python
import threading,time
def task1(n):
count =3
while (count):
count-=1
print("task 1 go ",n)
time.sleep(2)
def task2(n):
count =3
while (count):
count-=1
print("task 2 go ",n)
time.sleep(5)
start_time=time.time()
t1=threading.Thread(target=task1,args=("t1",)) # 创建线程t1
t2=threading.Thread(target=task2,args=("t2",)) # 创建线程t2
t1.start() # 运行线程t1
t2.start()
t1.join() # join: 主线程等子线程(t1)执行完后才往下走(执行print)
t2.join()
print(time.time()-start_time)
运行结果
python
import threading,time
def task1(n):
count = 3
while (count):
count-=1
print("task 1 go ",n)
time.sleep(2)
def task2(n):
count = 3
while (count):
count-=1
print("task 2 go ",n)
time.sleep(5)
start_time=time.time()
t1=threading.Thread(target=task1,args=("t1",)) # 创建线程t1
t2=threading.Thread(target=task2,args=("t2",)) # 创建线程t2
t1.start() # 运行线程t1
t2.start()
t1.join() # join: 主线程 等子线程(t1)执行完后才往下走(执行t2.join和print)
# t2.join()
print(time.time()-start_time)
运行结果
python
import threading,time
def task1(n):
count = 5
while (count):
count-=1
print("task 1 go ",n)
time.sleep(2)
def task2(n):
count = 3
while (count):
count-=1
print("task 2 go ",n)
time.sleep(5)
start_time=time.time()
t1=threading.Thread(target=task1,args=("t1",)) # 创建线程t1
t2=threading.Thread(target=task2,args=("t2",)) # 创建线程t2
t1.start() # 运行线程t1
t2.start()
t1.join() # join: 主线程 等子线程(t1)执行完后才往下走(执行t2.join和print)
# t2.join()
print(time.time()-start_time)
运行结果
1、threading.Thread 是 Python 标准库中用于创建线程的类。通过创建 Thread 对象,您可以将一个函数或可调用对象转换为一个独立的线程
除了 target 参数外,Thread 对象还可以接受其他一些参数,包括:
1)args:一个元组,用于传递给目标函数的参数。
2)kwargs:一个字典,用于传递给目标函数的关键字参数。
3)daemon:一个布尔值,指定线程是否为守护线程。如果设为 True,则主线程退出时它也会被强制退出
2、线程的运行顺序是并发的,而不是顺序的。也就是说,t1 和 t2 可能会交替运行,也可能会同时运行,取决于操作系统的调度策略
具体来说,主线程通过 t1.start() 和 t2.start() 启动了 t1 和 t2 两个线程。一旦启动,这两个线程就会并发地运行 task1 和 task2 函数。由于这两个函数内部包含了休眠时间,因此它们的执行顺序是不确定的
在多线程环境中,线程的运行顺序受到操作系统调度器的影响,调度器会根据一定的策略来决定哪个线程在某个时刻执行,因此无法确切地预测 t1 和 t2 的运行顺序。可能的情况包括:
1)t1 先执行完毕,然后 t2 执行完毕
2)t2 先执行完毕,然后 t1 执行完毕
3)t1 和 t2 交替执行,直到它们都执行完毕
3、主线程依次调用了 t1.join() 和 t2.join() 方法,因此 t1.join() 会在 t2.join() 之前执行。这意味着主线程会先等待线程 t1 执行完毕,然后再等待线程 t2 执行完毕
虽然 t1.join() 先于 t2.join() 执行,但由于 join() 方法会阻塞主线程,直到被调用的线程执行完毕,因此主线程最终会在等待 t1 和 t2 都执行完毕后才继续执行后续的代码
2.4 Socket 通信
c/s架构,多台客户端 能和 服务器通信
服务器端 IP地址,多个端口号(一个地址 也可以和多个客户端通信)
发送内容和接受内容 的过程可能会 有多次
代码中 用投诉中心 类比
服务器端
python
mport socket, threading
HOST_IP ='127.0.0.1' # 主机IP地址(127.0.0.1 表示本机自环测试)
# 类比: 投诉中心 总机电话号码
PORT = 9999 # 端口号(投诉中心的 分机号)
SIZE = 1024 # 每次接收的长度
SAVE_NAME = './save.jpg' # 接收到的文件(投诉记录文件)
# 接受数据线程(客服处理电话投诉)
def receive_thread(sock, addr):
print('Accept new connection from %s:%s...' % addr)
print("发送欢迎信息(如 这里是315投诉中心,请问你有什么诉求)")
sock.send(b'This is 315 complaint center. What do you want')
print('receiving, please wait for a second ...')
while True:
data = sock.recv(SIZE)
if not data :
print('reach the end of file')
break
else:
with open(SAVE_NAME, 'ab') as f:
f.write(data) # 接收数据存文件(把投诉问题用文件记录下来)
print("用文件,记录投诉问题")
print("关闭当前链接(挂断电话)")
sock.close() # 关闭当前链接(挂断电话)
print('receive finished')
print('Connection from %s:%s closed.' % addr)
# 创建一个socket(投诉中心 上班)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST_IP, PORT)) # 绑定IP和端口(这里的ip要在不同的情况下更改)
s.listen(1) # 开/始监听(每次只允许一个客户端接入)
# 类比: 客服待命,准备接听 消费者投诉电话
print('Waiting for connection...')
while True:
sock, addr = s.accept() # 接受client端新连接请求(接听投诉电话)
print("建立一个线程用来监听收到的数据,避免阻塞 (分配一客服来处理投诉)")
t = threading.Thread(target = receive_thread, args = (sock, addr))
t.start() # 线程运行,重新开始线程
运行,把本地的 image.jpg 传到了服务器端,生成了一个 save.jpg
客户端发送后 服务器端 结果
客户端
python
import socket
HOST_IP ='127.0.0.1' #主机IP地址(填写实际网卡IP地址,127.0.0.1时是做自环测试 )
#类比:投诉中心 总机电话号码
PORT = 9999 #端口号(投诉中心的 分机号)
SIZE = 1024 #每次接收的长度
FILENAME = './image.jpg' #待发送的文件
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("建立连接(打投诉中心电话)",HOST_IP,PORT)
s.connect((HOST_IP, PORT))
print("接收服务器接通时的回应的欢迎信息(如 这里是 315投诉中心,请问你有什么诉求)")
print(s.recv(SIZE))
print('sending, please wait for a second ...')
# 读取文件数据,并发送
with open(FILENAME, 'rb') as f:
for data in f:
s.send(data) #发送信息给服务器端(倾诉 投诉的内容)
print("倾诉 投诉的内容")
print('sended !')
s.close() #关闭链接(挂断电话)
print('connection closed(挂断电话)')
在命令行中运行,模拟另一台设备
把图片分成 一小段一小段内容 一段一段发送(也可以服务器端发送 客户端接受 都是可以的)
此时 服务器端 结果
服务器端 不断把 客户端发送的文件 记录下来
且并没有 退出,只是把 一个客户端发送的 处理完成了
如果再运行 客户端:
服务器端 一直 在准备接受 新的请求
2.5 python调用C
把C代码 封装成 Python的一个库,来使用
add.c
c
#include <stdio.h>
int add_int(int, int); // 对外的接口,跟函数 放在一个文件中
int add_int(int num1, int num2){
printf("add num1+num2\n");
return num1 + num2;
}
gcc -shared -Wl,-soname,adder -o adder.so -fPIC add.c
在Linux编译生成动态库,C文件名是 add.c 库文件名是 adder.so
使用
python
from ctypes import *
adder = CDLL('./adder.so') # load c share lib,使用C库,adder指向库的引用,二进制库
print(adder.add_int(4,5))
运行结果