python基础 | 核心库:自定义库,标准库(时间,文件操作(附struct库),多线程,socket通信,python调用C)

python库相当丰富, 需要时候再去找去查,使用方便
这里只是冰山一角

1、自定义库(模块)

跟C中的#include一致
sum.py

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中的函数

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__':

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)

再运行use.py
运行代码结果

运行sum.py会执行 测试代码
运行结果

if __name__ == '__main__' 是 Python 中一个常见的 条件语句,用于检查 当前模块是否作为 主程序执行,还是 被导入到其他模块中
当 Python 解释器执行一个文件时,会将其作为一个模块载入,并为该模块指定一个特殊的名称 __name__。如果一个模块是 作为主程序执行,那么其 __name__ 属性的值就会被设置为 '__main__',反之,如果模块是 被导入到其他模块中,那么 __name__ 的值就会是 该模块的名称

1.2 模块的定义和使用

my_module.py 定义自己的模块

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 使用模块

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 之前的所有整数

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命令

import os
print(os.system('ls'))  #执行Linux系统命令ls

执行Linux系统命令ls,跟直接输入 ls一样的
运行结果
检测文件,目录

if os.path.exists('/etc/passwd'):    #检测文件存在否
	print('file passwd exits')
print(os.path.isfile('/etc/passwd')) #检测是文件否,而不是文件夹
print(os.path.isdir('/etc'))         #检测是目录否  

运行结果:
运行结果
获取目录,路径名,文件名,列举目录下的文件

print(os.getcwd())                     #获取当前目录
print(os.path.dirname('/etc/passwd'))	 #获取路径名,即文件上一层所在的路径,可以方便 把文件存在同一个目录下面
print(os.path.basename('/etc/passwd')) #获取文件名    
print(os.listdir('/etc'))  #列举目录下的文件

运行结果:
运行结果
创建目录,重命名:

os.mkdir("dir")        #创建目录(文件夹)
os.rename("hello.py","helloPython.py")  #重命名

当前目录名称,子目录名称,子文件名称;遍历目录下所有文件;将多个路径组合后返回

#遍历目录下所有文件
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、文件读写
存图片,存数据库相关的信息,从本地读出来,通过网络传输,需要操作文件

# 本地的话不需要把路径写全,写文件名就行
fd = open('file') #默认只读打开,在一个文件夹内 只要写名字,fd里面存储了文件对象,文件名不存在报错
# 文件对象的相关的方法(封装好的)
print(fd.read())   #读完文件
fd.close()         #关闭文件,虽然会自动退出,但是还是加一下,避免别人操作这个文件,关闭了就访问不了了

读取到了文件里的信息
运行结果

写打开

fd = open('newfile','w')  #写打开,(如不存在则创建)
fd.write('overflow\n') #覆盖写入+换行
fd.write('add') #追加写入

覆盖写入,再追加信息
newfile文件内容
文件内容

追加方式打开

fd = open('file','a')  #追加方式打开
print(fd.write('append')) #追加其后

追加后文件内容
文件内容
但是不允许读

print(fd.read())

运行结果
读写打开,位置偏移

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())    #读一行

运行结果
文件内容

运行结果
二进制读取

data_file = 'MNIST_data/train-images-idx3-ubyte.gz'
print(open(data_file, 'rb').read(32))     #rb:二进制读取

运行结果
运行结果
转回 utf-8,with 会自动释放资源(省去close)

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)

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()

运行结果:
运行结果
以读写的方式打开二进制文件

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数据类型

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 多线程

线程与进程

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)	

运行结果
运行结果1

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)	

运行结果
运行结果

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地址,多个端口号(一个地址 也可以和多个客户端通信)
发送内容和接受内容 的过程可能会 有多次

通信过程
代码中 用投诉中心 类比

服务器端
server.py

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

运行结果

客户端发送后 服务器端 结果

服务器端 结果信息

客户端
client.py

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

#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
运行结果
使用

from ctypes import *

adder = CDLL('./adder.so') # load c share lib,使用C库,adder指向库的引用,二进制库
print(adder.add_int(4,5))

运行结果
运行结果

  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值