首页 > 其他分享 >模块与包

模块与包

时间:2024-10-31 13:33:13浏览次数:6  
标签:logging 模块 print path 日志 os

模块和包

什么是模块?

在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。

为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Python中,一个.py文件就称之为一个模块(Module)。

模块即一个py文件

模块分为三种

	1.python标准库
	2.第三方模块
	3.自定义模块

另外,使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。

定义规范

1、定义模块名称不能以数字开头
2.不能和默认模块重名

定义格式

开头:
	介绍模块的作用
	里面包含的功能
	作者的联系方式等等

模块定义

"""
变量
输出*	
"""

star = "**********"
"我的作用是付了10个星号"

def p_stat():
    "我的作用是返回20个星号"
    return "*"*20

模块导入

1. import 模块名1 [as 别名1], 模块名2 [as 别名2],…:使用这种语法格式的 import 语句,会导入指定模块。不仅如此,当需要使用模块中的成员时,需用该模块名(或别名)作为前缀,否则 Python 解释器会报错。
2. from 模块名 import 成员名1 [as 别名1],成员名2 [as 别名2],…: 使用这种语法格式的 import 语句,只会导入模块中指定的成员,而不是全部成员。同时,当程序中使用该成员时,无需附加任何前缀,直接使用成员名(或别名)即可。

注意:

1、用 [] 括起来的部分,可以使用,也可以省略。
2、其中,第二种 import 语句也可以导入指定模块中的所有成员,即使用 form 模块名 import *,但此方式不推荐使用,

__all__可以进行限制

__name__

Make a .py both importable and executable

如果我们是直接执行某个.py文件的时候,该文件中那么__name__ == "main"是True,但是我们如果从另外一个.py文件通过import导入该文件的时候,这时name的值就是我们这个py文件的名字而不是main。

这个功能还有一个用处:调试代码的时候,在”if name == 'main'“中加入一些我们的调试代码,我们可以让外部模块调用的时候不执行我们的调试代码,但是如果我们想排查问题的时候,直接执行该模块文件,调试代码能够正常运行!

示例 打印出20个星号
创建一个功能模块,该模块可以被调用import
在模块中包含一个功能函数,函数的作用返回20个hello

import printstar

"""
#print(dir(printstar)) 列出属性
# print(printstar.p_star())   打印出20个星号

#print(printstar.star) 打印出10个星星
"""

star20 = printstar.p_star()
print(star20)
print("hello")
print((printstar.star)*2)	

包:一个包就是一个文件夹(一个包含__init__.py的文件夹)

导包秘密
sys.path

1.解释器按照sys.path的路径模块与包的导入
2.解释器执行一个程序会将启动程序文件的目录添加到sys.path

导包路径

绝对路径导包: os.listdir(os.getcwd()) 使用os模块获取当前路径,插入到sys.path路径列表里面去
相对路径导包:. 当前路径 ..上层路径 不建议使用

导包三种方式

	1 from 报名 import 模块名
	
	2 from 包1.包2.包3 import 模块名
		支持:from 包1.包2.包3.模块名 import 成员变量
		支持:from 包1.包2.包3 import 模块名
		不支持:from 包1.包2 import 包3.成员变量
	
	3 import 包
		不支持 包.模块。成员变量

subprocess模块

subprocess是python 2.4中新增的模块,它允许你生成新的进程,连接到他们的input/output/erro管道,并获取他们的返回码。这个模块的目的在于替换几个旧的模块和方法。

  • os.system
  • os.spawn*

subprocess模块中的常用函数

函数 描述
subprocess.run() python 3.5中新增的函数,执行指定的命令,等待命令执行完成后返回一个包含执行结果的CompletedProcess类的实例。
subprocess.call() 执行指定的命令,返回命令执行
subprocess.check_call() python 2.5中新增的函数。执行指定的命令,如果执行成功则返回状态码,否则抛出异常,其功能等价于subprocess.run(...,ckeck=True)
subprocess.check_output python2.7中新增的函数,执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。
subprocess.getoutput(cmd) 接收字符串格式的命令,执行命令并返回执行结果,其功能类似于os.popen(cmd).read()和commands.getoutput(cmd)
subprocess.getstatusoutput(cmd) 执行cmd命令,返回一个元组(命令执行状态, 命令执行结果输出),其功能类似于commands.getstatusoutput()。

说明:

  • 1.在Python 3.5之后的版本中,官方文档中提倡通过subprocess.run()函数替代其他函数来使用subproccess模块的功能;
  • 2.在Python 3.5之前的版本中,我们可以通过subprocess.call(),subprocess.getoutput()等上面列出的其他函数来使用subprocess模块的功能;
  • 3.subprocess.run()、subprocess.call()、subprocess.check_call()和subprocess.check_output()都是通过对subprocess.Popen的封装来实现的高级函数,因此如果我们需要更复杂功能时,可以通过subprocess.Popen来完成。
  • 4.subprocess.getoutput()和subprocess.getstatusoutput()函数是来自Python 2.x的commands模块的两个遗留函数。它们隐式的调用系统shell,并且不保证其他函数所具有的安全性和异常处理的一致性。另外,它们从Python 3.3.4开始才支持Windows平台。

2. 上面各函数的定义及参数说明
函数参数列表:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, universal_newlines=False)

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)

subprocess.getstatusoutput(cmd)

subprocess.getoutput(cmd)

参数说明:

  • args: 要执行的shell命令,默认应该是一个字符串序列,如['df', '-Th']或('df', '-Th'),也可以是一个字符串,如'df -Th',但是此时需要把shell参数的值置为True。

  • shell: 如果shell为True,那么指定的命令将通过shell执行。如果我们需要访问某些shell的特性,如管道、文件名通配符、环境变量扩展功能,这将是非常有用的。当然,python本身也提供了许多类似shell的特性的实现,如glob、fnmatch、os.walk()、os.path.expandvars()、os.expanduser()和shutil等。

  • check: 如果check参数的值是True,且执行命令的进程以非0状态码退出,则会抛出一个CalledProcessError的异常,且该异常对象会包含 参数、退出状态码、以及stdout和stderr(如果它们有被捕获的话)。

  • stdout, stderr:input: 该参数是传递给Popen.communicate(),通常该参数的值必须是一个字节序列,如果universal_newlines=True,则其值应该是一个字符串。

run()函数默认不会捕获命令执行结果的正常输出和错误输出,如果我们向获取这些内容需要传递subprocess.PIPE,然后可以通过返回的CompletedProcess类实例的stdout和stderr属性或捕获相应的内容;

call()和check_call()函数返回的是命令执行的状态码,而不是CompletedProcess类实例,所以对于它们而言,stdout和stderr不适合赋值为subprocess.PIPE;

check_output()函数默认就会返回命令执行结果,所以不用设置stdout的值,如果我们希望在结果中捕获错误信息,可以执行stderr=subprocess.STDOUT。

  • universal_newlines: 该参数影响的是输入与输出的数据格式,比如它的值默认为False,此时stdout和stderr的输出是字节序列;当该参数的值设置为True时,stdout和stderr的输出是字符串。

struct

用处

1.按照指定格式将python数据转换为字符串,该字符串为字节流,如网络传输时,不能传输int,此时现将int转换为字节流,然后再发送。
2.按照指定格式将字节流转换为python指定的数据类型。
3.处理二进制数据,如果用struct来处理文件的话,需要用“wb”,"rb"以二进制(字节流)写读的方式来处理文件;
4.处理C语言中的结构体

struct模块中的函数

函数 return explain
pack(fmt,v1,v2...) string 按照给定的格式(fmt),把数据转化成字符串(字节流),并将该字符串返回
pack_into(fmt,buffer,offset,v1,v2…) None 按照给定的格式(fmt),将数据转换层字符串(字节流)并将字节流写入以offset开始的buffer中。(buffer为可写的缓冲区,可用array模块)
unpack(fmt,v1,v2…..) tuple 按照给定的格式(fmt)解析字节流,并返回解析结果
pack_from(fmt,buffer,offset) tuple 按照给定的格式(fmt)解析以offset开始的缓冲区,并返回解析结果
calcsize(fmt) size of fmt 计算给定的格式(fmt)占用多少字节的内存,注意对齐方式

格式化字符串

当打包或者解包时,需要按照特定的方式来打包或者解包,该方法就是格式化字符串,他指定了数据类型,除此之外,还有用于控制字节流顺序,大小和对齐方式的特殊字符。

对齐方式

为了同C中的结构体交换数据,还要考虑c或c++编译器使用了字节对齐,通常是以4个字节为单位的32位系统,故而struct根据本地机器字节顺序转换,可以用格式中的第一个字符来改变对齐方法

Character Byte order Size Alignment
@(默认) 本机 本机 本机,凑够4字节
= 本机 标准 none,按原字节数
< 小端 标准 none,按原字节数
> 大端 标准 none,按原字节数
! network(大端) 标准 none,按原字节数

格式符

格式符 C语言类型 Python类型 Standard size
x pad byte(填充字节) no value
c char string of length 1 1
b signed char integer 1
B unsigned char integer 1
? _Bool bool 1
h short integer 2
H unsigned short integer 2
i int integer 4
I(大写的i) unsigned int integer 4
l(小写的L) long integer 4
L unsigned long long 4
q long long long 8
Q unsigned long long long 8
f float float 4
d double float 8
s char[] string
p char[] string
P void * long

  • _Bool在C99中定义,如果没有这个类型,则将这个类型视为char,一个字节;
  • q和Q只适用于64位机器;
  • 每个格式前可以有一个数字,表示这个类型的个数,如s格式表示一定长度的字符串,4s表示长度为4的字符串;4i表示四个int;
  • P用来转换一个指针,其长度和计算机相关;
  • f和d的长度和计算机相关;
import struct

data = struct.pack("i",234)		#转换为固定字节流
print("data:",data)
print(struct.unpack("i",data))		#将字节流转换为元组

结果:
data: b'\xea\x00\x00\x00'
(234,)

sys

sys模块是与解释器交互的一个模块

sys.path	当前sys中的路径
sys.argv		命令行参数list,第一个元素是程序本身路径
sys.exit()	退出程序,正常退出是exit()
sys.version     #获取python解释器程序的版本信息
sys.maxint  	#最大的int值
sys.path    	#返回模块的搜索路径,初始化pythonpath的环境变量的值
sys.platform    #返回操作系统平台名称

OS模块

一个用于处理文件和目录的模块

os模块是与操作系统交互的一个接口

os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd
os.curdir  返回当前目录: ('.')
os.pardir  获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2')    可生成多层递归目录
os.removedirs('dirname1')    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname')    生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname')    删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname')    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove()  删除一个文件
os.rename("oldname","newname")  重命名文件/目录
os.stat('path/filename')  获取文件/目录信息
os.sep    输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep    输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command")  运行shell命令,直接显示
os.environ  获取系统环境变量
os.path.abspath(path)  返回path规范化的绝对路径
os.path.split(path)  将path分割成目录和文件名二元组返回
os.path.dirname(path)  返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path)  返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  如果path是绝对路径,返回True
os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path)  返回path所指向的文件或者目录的最后访问时间
os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小

1.当前路径及路径下的文件

os.getcwd():查看当前所在路径。
os.listdir(path):列举目录下的所有文件。返回的是列表类型。

import os
print(os.getcwd())  #查看当前所在路径
print(os.listdir(os.getcwd()))  #列举目录下所有的文件,返回的是列表类型

file 当前文件
os.path.abspath(file) 当前文件路径
os.path.dirname(os.path.abspath(file))当前文件的文件夹路径

hashlib模块

算法介绍

python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。
是不可以回溯的。只能加密不能解密

MD5是最常见的摘要算法,速度很快,生成结果是固定的16字节,通常用一个32位的16进制字符串表示。SHA1算法更安全点,它的结果是20字节长度,通常用一个40位的16进制字符串表示。而比SHA1更安全的算法是SHA256和SHA512等等,不过越安全的算法越慢,并且摘要长度更长。

单个加密

import hashlib      #调用模块
hd = hashlib.md5()  #定义变量
s1 = "li".encode()  #字符串内容编码
hd.update(s1)       #加密
print(hd.hexdigest())   #输出加密字符,

结果:d70c1e5d44de8a9150eb91ecff563578

加密多个结果

import hashlib      #调用模块

hd = hashlib.md5()  #定义变量
s1 = "li".encode()  #字符串内容编码
s2 = "ww".encode()
hd.update(s2)       #加密
hd.update(s1)
print(hd.hexdigest())   #输出加密字符 b71634e4bf21207a98247028775cd4ab

等同于

import hashlib      #调用模块
hd = hashlib.md5()  #定义变量
s3 = "liww".encode()
hd.update(s3)
print(hd.hexdigest()) #b71634e4bf21207a98247028775cd4ab

多个加密内容:hexdigest会将两个加密内容组合到一起,进行加密

MD5()加默认值

import hashlib
md = hashlib.md5("qwe".encode())
pwd = "123".encode()
md.update(pwd)
print(md.hexdigest())  #200820e3227815ed1756a6b531e7e0d2

等同于

import hashlib
md = hashlib.md5()
# print("qwe".encode())
pwd = "123".encode()
md.update("qwe123".encode())
print(md.hexdigest())  #200820e3227815ed1756a6b531e7e0d2

在update时,md5的值会放在update内容前面

__init__文件

init.py该文件的作用就是相当于把自身整个文件夹当作一个包来管理,每当有外部导入的时候会自动执行里面的代码。

导入包的时候,默认会执行__init文件

主要功能

1. 标识该目录是一个python的模块包(module package)
如果你是使用python的相关IDE来进行开发,那么如果目录中存在该文件,该目录就会被识别为 module package 。

2. 简化模块导入操作

3.控制模块导入

4.偷懒的导入方法

__all__ 关联了一个模块列表,当执行 from xx import * 时,就会导入列表中的模块。

5. 配置模块的初始化操作

在了解了__init__.py的工作原理后,应该能理解该文件就是一个正常的python代码文件。
因此可以将初始化代码放入该文件中。

__all__ = [""]  

作用: 在import导包时候 使用*导入成员变量时,可以使用__all__ 限制导入包的成员斌量。

使用*时,会导入__all__列表里面的成员变量

示例

//定义两个文件夹,在protao文件夹中定义day5包,里面创建函数,并在__init__中打印输出内容。
//在pro文件夹定义main包,里面去调用day5中定义的函数

定义内容

protao文件夹内容

//__init__
print("__init__")


//day5
__all__ = ["x","day5"]
x = 10
y = 20
def day5():
    print("5day")
pro文件夹内容

//main
import os
import sys

ww = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))	#取出上层文件夹路径
sys.path.append(ww)		#将上层文件夹路径加入到系统变量中

from protao.day5 import *	#调用protao.day5中的所有成员元素
day5()		
print(x)
print(y)
#因为y没有在__all__中定义,所以在导入所有包的时候是找不到的y这个变量的,x和day5在__all__中定义了,所以是可以找到的的


re模块

就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。

功能:针对字符串实现模糊匹配

正则符号

//元字符
. :通配符:除换行符以外的任意一个符号
^ :以..开头
$ :以..结尾

//重复符号
* :前一个字符重复0~n次
+ :前一个字符重复1~n次
? :前一个字符重复0~1次
{}:任意指定次数
	{n,}:前一字符最少出现n次
	{,n}:钱一个字符最多出现0~n次



() :表示一个整体
[] :匹配[]中指定范围内的任意一个字符
	[abc]相当于是一个符号(每次匹配一个字符)找出包含a或b或c

\ :转移符号
	\d:匹配任何十进制数,相当于[0-9]
	\D:匹配任何非数字字符;相当于[^0-9]
	\s:空表字符:空格 \t\r\n\f\v
	\S:非空白字符
	\w:单词字符:[A-Za-z0-9~]
	\W:非单词字符
	\b:匹配一个特殊字符,比如空格 , & #等
- :表示一个范围
	1-9:表示1-9的所有数字
| :或者

字符集

[^] :取反,非
ret = re.findall("c[^0-9]+e","coe,c12e,cwe,c.e c8e")
print(ret)  #['coe', 'cwe,c.e']

贪婪匹配

满足匹配时,在满足匹配时,匹配尽可能的长的字符串,在匹配时默认贪婪匹配

ret = re.findall("a.*c","abcabcabu")
print(ret)	#['abcabc']
//取消贪婪匹配
ret = re.findall("a.*?c","abcabcabu")
print(ret)	#['abc', 'abc']

取消贪婪匹配 ?

.findall

将匹配的所有的内容放在一个列表里面

re.findall("规则","待匹配字符串")

.search()

函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以
通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。

re.search("规则","待匹配字符串")
ret = 'www.baidu.com,www.oldboy.com,www.jd.com'
ret2 = re.search("www.(baidu|oldboy|jd).com",ret)
print(ret2)  #<_sre.SRE_Match object; span=(0, 13), match='www.baidu.com'>
print(ret2.group()) #www.baidu.com  #元素值
print(ret2.span())  #(0, 13)    #索引位置

.match()

同search,不过尽在字符串开始处进行匹配

ret = 'www.baidu.com,www.oldboy.com,www.jd.com'
ret2 = re.match("www.(baidu|oldboy|jd).com",ret)
print(ret2)  #<_sre.SRE_Match object; span=(0, 13), match='www.baidu.com'>
print(ret2.group()) #www.baidu.com
print(ret2.span())  #(0, 13)

.split()

分割

ret = "hello,world alvin|yuan"
print(ret.split(","))   #['hello', 'world alvin|yuan']
print(re.split("[, |]",ret))    #['hello', 'world', 'alvin', 'yuan']

compile()
编译正则表达式模式,返回一个对象的模式。(可以把那些常用的正则表达式编译成正则表达式对象,这样可以提高一点效率。)

obj = re.compile("\d{3}")
ret = obj.search('abc123wwww')
print(ret)  #<_sre.SRE_Match object; span=(3, 6), match='123'>
print(ret.group())  #123
ret = obj.search("12sdf34sd446xcfg433")
print(ret)  #<_sre.SRE_Match object; span=(9, 12), match='446'>
print(ret.group())  #446

示例

完全匹配

whl = "welome to Python Wolrd! Python is nice!"

ret = re.findall("Python",whl)
print(ret)  #['Python', 'Python']

. 点

ret = "room zoom home yoom"
print(re.findall(".oo.",ret))   #['room', 'zoom', 'yoom']
print(re.findall("h..e",ret))   #['home']

^ $

whl = "welome to Python Wolrd! Python is nice!"

print(re.findall("^to",whl))    #[]
print(re.findall("^w",whl)) #['w']
print(re.findall("^we",whl))    #['we']
print(re.findall("Wolrd$",whl)) #[]
print(re.findall("ce!",whl))    #['ce!']
print(re.findall("^weomenice$",whl))    #[]
print(re.findall("^welome.*nice!$",whl))    #['welome to Python Wolrd! Python is nice!']

* + ? {}

ret = "come  commmme  hi coe yuan comme hello world commmmmme"
print(re.findall("com*e",ret))      #['come', 'commmme', 'coe', 'comme', 'commmmmme']
print(re.findall("com+e",ret))      #['come', 'commmme', 'comme', 'commmmmme']
print(re.findall("com?e",ret))      #['come', 'coe']
print(re.findall("com{4}e",ret))    #['commmme']
print(re.findall("com{,4}e",ret))   #['come', 'commmme', 'coe', 'comme']
print(re.findall("com{4,}e",ret))   #['commmme', 'commmmmme']

[] ()

ret = "abd acd abcd a,d ad"
print(re.findall("a[bc]d",ret))     #['abd', 'acd']
print(re.findall("a[b,c]d",ret))    #['abd', 'acd', 'a,d']

num = "12,45,67,89,0,yuan,Alvin,100"
print(re.findall("[1-8]+",num))     #['12', '45', '67', '8', '1']
print(re.findall("\w+",num))        #['12', '45', '67', '89', '0', 'yuan', 'Alvin', '100']

print(re.findall('www.(baidu|jd|tb).com',"'www.baidu.com,www.tb.com,www.jd.com'"))  #['baidu', 'tb', 'jd']
# //取消优先获取
print(re.findall('www.(?:baidu|jd|tb).com',"'www.baidu.com,www.tb.com,www.jd.com'"))  #['www.baidu.com', 'www.tb.com', 'www.jd.com']

json模块

json就是序列化和反序列化的过程

join序列化:将本语言支持的数据对象转换为join字符串的过程
join反序列化:将join字符串转换为本语言支持的数据对象的过程

语法

//序列化
json.dumps(n)

//反序列化
json.loads()

原文

s = "hi,li"
b = True
i = 100
l = ['s','b','i']
d = {'name':"li","age":18,"hobby":None}

序列化方法

转换为json字符串

print(json.dumps(s))    #"hi,li"
print(json.dumps(b))    #true
print(json.dumps(i))    #100
print(json.dumps(l))    #["s", "b", "i"]
print(json.dumps(d))    #{"name": "li", "age": 18, "hobby": null}

将json字符串存储到文件中

f = open("json.txt","a")
f.write(json.dumps(s)+"\n")
f.write(json.dumps(i)+"\n")
f.write(json.dumps(l)+"\n")
f.write(json.dumps(d)+"\n")
f.close()

反序列化

将json字符串转换为python文件

反序列化一行

with open("json.txt","r") as f:
    json_str = f.read()
print(json_str)

#反序列化 loads
date = json.loads(json_str)
print(date)
print(type(date))

反序列化多行

with open("json.txt","r") as f:
    for i in f:
        print(i,end="")
        date = json.loads(i)
        print(date)
        print(type(date))

logging日志模块

日志是一种可以追溯某些软件运行时所发生的的事件的方法,

日志级别

级别 使用场景
DEBUG 详细信息,典型的调试问题时会感兴趣
INFO 证明事情按预期工作,关键时间
WARNING 表名发生一些意外,或者不久的将来发生的问题。软件还在正常工作
ERROR 由于更严重的问题,软件已不能执行一些功能了,一般错误信息
CRITICAL 严重错误,表明软件已不能继续运行了
NOTICE 不是错误,但是需要处理,普通但是重要的事件
ALERT 需要立即修复,例如系统数据库损坏
EMERGENCY 紧急情况,系统不可用,一般会通知所有用户

一条日志信息对应的是一个事件的发生,而一个事件通常需要包括以下几个内容:

  • 事件发生时间
  • 事件发生位置
  • 事件的严重程度--日志级别
  • 事件内容

上面这些都是一条日志记录中可能包含的字段信息,当然还可以包括一些其他信息,如进程ID、进程名称、线程ID、线程名称等。日志格式就是用来定义一条日志记录中包含那些字段的,且日志格式通常都是可以自定义的。

debug < info < warning < ERROR < CRITICAL

logging模块的日志级别:

logging模块默认定义了以下几个日志等级,它允许开发人员自定义其他日志级别,但是这是不被推荐的,尤其是在开发供别人使用的库时,因为这会导致日志级别的混乱。

日志等级(level) 描述
DEBUG 最详细的日志信息,典型应用场景是 问题诊断
INFO 信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作
WARNING 当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的
ERROR 由于一个更严重的问题导致某些功能不能正常运行时记录的信息
CRITICAL 当发生严重错误,导致应用程序不能继续运行时记录的信息

开发应用程序或部署开发环境时,可以使用DEBUG或INFO级别的日志获取尽可能详细的日志信息来进行开发或部署调试;

应用上线或部署生产环境时,应该使用WARNING或ERROR或CRITICAL级别的日志来降低机器的I/O压力和提高获取错误日志信息的效率。日志级别的指定通常都是在应用程序的配置文件中进行指定的。

logging默认warning级别,只有大于等于warning级别的日志才会显示
日志是默认以追加的方式写入到文件中的

导入模块

import logging

获取日志有两种方法

1.日志模块1.
	logging.basicConfig
2.日志模块2  日志对象
	logging.getLogger

logging.basicConfig模块

设置日志

import logging
LOG_FORMAT = "%(asctime)s %(name)s %(levelname)s %(pathname)s %(message)s "#配置输出日志格式
DATE_FORMAT = '%Y-%m-%d  %H:%M:%S %a ' #配置输出时间的格式,注意月份和天数不要搞乱了
logging.basicConfig(level=logging.DEBUG,
                    format=LOG_FORMAT,
                    datefmt = DATE_FORMAT ,
                    filename=r"d:\test\test.log" #有了filename参数就不会直接输出显示到控制台,而是直接写入文件
                    )
logging.debug("msg1")
logging.info("msg2")
logging.warning("msg3")
logging.error("msg4")
logging.critical("msg5")

//修改logging默认级别为DEBUG

logging.basicConfig(level=logging.DEBUG,     #配置默认日志界别
                    filename="logs.log",        #配置日志输出路径
                    format="%(asctime)s:%(name)s:%(message)s %(levelname)s,行数:%(lineno)s",       #定义日志输出格式
                    datefmt="%Y%m%d %H:%M:%S"	#添加事件输出
                    )


//使用logger对象进行日志记录
logging.debug("DEBUG信息")
logging.info("info信息")
logging.warning("warning信息")
logging.error("error信息")
logging.critical("critical信息")

logging.basicConfig()函数包含参数说明

参数名称 描述
filename 指定日志输出目标文件的文件名(可以写文件名也可以写文件的完整的绝对路径,写文件名日志放执行文件目录下,写完整路径按照完整路径生成日志文件),指定该设置项后日志信心就不会被输出到控制台了
filemode 指定日志文件的打开模式,默认为'a'。需要注意的是,该选项要在filename指定时才有效
format 指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序。logging模块定义的格式字段下面会列出。
datefmt 指定日期/时间格式。需要注意的是,该选项要在format中包含时间字段%(asctime)s时才有效
level 指定日志器的日志级别
stream 指定日志输出目标stream,如sys.stdout、sys.stderr以及网络stream。需要说明的是,stream和filename不能同时提供,否则会引发 ValueError异常
style Python 3.2中新添加的配置项。指定format格式字符串的风格,可取值为'%'、'{'和'$',默认为'%'
handlers Python 3.3中新添加的配置项。该选项如果被指定,它应该是一个创建了多个Handler的可迭代对象,这些handler将会被添加到root logger。需要说明的是:filename、stream和handlers这三个配置项只能有一个存在,不能同时出现2个或3个,否则会引发ValueError异常。

logging模块中定义好的可以用于format格式字符串说明

字段/属性名称 使用格式 描述
asctime %(asctime)s 将日志的时间构造成可读的形式,默认情况下是‘2016-02-08 12:00:00,123’精确到毫秒
name %(name)s 所使用的日志器名称,默认是'root',因为默认使用的是 rootLogger
filename %(filename)s 调用日志输出函数的模块的文件名; pathname的文件名部分,包含文件后缀
funcName %(funcName)s 由哪个function发出的log, 调用日志输出函数的函数名
levelname %(levelname)s 日志的最终等级(被filter修改后的)
message %(message)s 日志信息, 日志记录的文本内容
lineno %(lineno)d 当前日志的行号, 调用日志输出函数的语句所在的代码行
levelno %(levelno)s 该日志记录的数字形式的日志级别(10, 20, 30, 40, 50)
pathname %(pathname)s 完整路径 ,调用日志输出函数的模块的完整路径名,可能没有
process %(process)s 当前进程, 进程ID。可能没有
processName %(processName)s 进程名称,Python 3.1新增
thread %(thread)s 当前线程, 线程ID。可能没有
threadName %(thread)s 线程名称
module %(module)s 调用日志输出函数的模块名, filename的名称部分,不包含后缀即不包含文件后缀的文件名
created %(created)f 当前时间,用UNIX标准的表示时间的浮点数表示; 日志事件发生的时间--时间戳,就是当时调用time.time()函数返回的值
relativeCreated %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数; 日志事件发生的时间相对于logging模块加载时间的相对毫秒数
msecs %(msecs)d 日志事件发生事件的毫秒部分。logging.basicConfig()中用了参数datefmt,将会去掉asctime中产生的毫秒部分,可以用这个加上

说明

1. logging.basicConfig()函数是一个一次性的简单配置工具使,也就是说只有在第一次调用该函数时会起作用,后续再次调用该函数时完全不会产生任何操作的,多次调用的设置并不是累加操作。
2. 如果要记录的日志中包含变量数据,可使用一个格式字符串作为这个事件的描述消息(logging.debug、logging.info等函数的第一个参数),然后将变量数据作为第二个参数*args的值进行传递,如:
       logging.warning('%s is %d years old.', 'Tom', 10),
   输出内容为
       WARNING:root:Tom is 10 years old.

日志模块使用方式2 日志流处理流程

日志流处理流程是一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)。

logging日志模块四大组件:

在介绍logging模块的日志流处理流程之前,我们先来介绍下logging模块的四大组件:

组件名称 对应类名 功能描述
日志器 Logger 提供了应用程序可一直使用的接口
处理器 Handler 将logger创建的日志记录发送到合适的目的输出
过滤器 Filter 提供了更细粒度的控制工具来决定输出哪条日志记录,丢弃哪条日志记录
格式器 Formatter 决定日志记录的最终输出格式

logging模块就是通过这些组件来完成日志处理的,上面所使用的logging模块级别的函数也是通过这些组件对应的类来实现的。

这些组件之间的关系描述:

  • 日志器(logger)需要通过处理器(handler)将日志信息输出到目标位置,如:文件、sys.stdout、网络等;
  • 不同的处理器(handler)可以将日志输出到不同的位置;
  • 日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置;
  • 每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志;
  • 每个处理器(handler)都可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方。

简单点说就是:日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。

(1) Handler类:

Handler对象的作用是(基于日志消息的level)将消息分发到handler指定的位置(文件、网络、邮件等)。Logger对象可以通过addHandler()方法为自己添加0个或者更多个handler对象。比如,一个应用程序可能想要实现以下几个日志需求:

  1. 把所有日志都发送到一个日志文件中;
  2. 把所有严重级别大于等于error的日志发送到stdout(标准输出);
  3. 把所有严重级别为critical的日志发送到一个email邮件地址。这种场景就需要3个不同的handlers,每个handler复杂发送一个特定严重级别的日志到一个特定的位置。
Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略``Handler.setFormatter():给这个handler选择一个格式``Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个``filter``对象

需要说明的是,应用程序代码不应该直接实例化和使用Handler实例。因为Handler是一个基类,它只定义了素有handlers都应该有的接口,同时提供了一些子类可以直接使用或覆盖的默认行为。下面是一些常用的Handler:

Handler 描述
logging.StreamHandler 将日志消息发送到输出到Stream,如std.out, std.err或任何file-like对象。
logging.FileHandler 将日志消息发送到磁盘文件,默认情况下文件大小会无限增长
logging.handlers.RotatingFileHandler 将日志消息发送到磁盘文件,并支持日志文件按大小切割
logging.hanlders.TimedRotatingFileHandler 将日志消息发送到磁盘文件,并支持日志文件按时间切割
logging.handlers.HTTPHandler 将日志消息以GET或POST的方式发送给一个HTTP服务器
logging.handlers.SMTPHandler 将日志消息发送给一个指定的email地址
logging.NullHandler 该Handler实例会忽略error messages,通常被想使用logging的library开发者使用来避免'No handlers could be found for logger XXX'信息的出现。

(2) Formater类:

Formater对象用于配置日志信息的最终顺序、结构和内容。与logging.Handler基类不同的是,应用代码可以直接实例化Formatter类。另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个Formatter的子类来完成。

Formatter类的构造方法定义如下:

    logging.Formatter.__init__(fmt``=``None``, datefmt``=``None``, style``=``'%'``)

可见,该构造方法接收3个可选参数:

  • fmt:指定消息格式化字符串,如果不指定该参数则默认使用message的原始值
  • datefmt:指定日期格式字符串,如果不指定该参数则默认使用"%Y-%m-%d %H:%M:%S"
  • style:Python 3.2新增的参数,可取值为 '%', '{'和 '$',如果不指定该参数则默认使用'%'

一般直接用logging.Formatter(fmt, datefmt)

(3) Filter类(暂时了解)

Filter可以被Handler和Logger用来做比level更细粒度的、更复杂的过滤功能。Filter是一个过滤器基类,它只允许某个logger层级下的日志事件通过过滤。该类定义如下:

    class logging.Filter(name='')
        filter(record)

比如,一个filter实例化时传递的name参数值为'A.B',那么该filter实例将只允许名称为类似如下规则的loggers产生的日志记录通过过滤:'A.B','A.B,C','A.B.C.D','A.B.D',而名称为'A.BB', 'B.A.B'的loggers产生的日志则会被过滤掉。如果name的值为空字符串,则允许所有的日志事件通过过滤。

filter方法用于具体控制传递的record记录是否能通过过滤,如果该方法返回值为0表示不能通过过滤,返回值为非0表示可以通过过滤。

说明:

  1. 如果有需要,也可以在filter(record)方法内部改变该record,比如添加、删除或修改一些属性
  2. 我们还可以通过filter做一些统计工作,比如可以计算下被一个特殊的logger或handler所处理的record数量等。

日志流处理简要流程:

1、创建一个logger
 
2、设置下logger的日志的等级
 
3、创建合适的Handler(FileHandler要有路径)
 
4、设置下每个Handler的日志等级
 
5、创建下日志的格式
 
6、向Handler中添加上面创建的格式
 
7、将上面创建的Handler添加到logger中
 
8、打印输出logger.debug\logger.info\logger.warning\logger.error\logger.critical

示例

# 代码
import logging
def log():
    #创建logger,如果参数为空则返回root logger
    logger = logging.getLogger("nick")
    logger.setLevel(logging.DEBUG)  #设置logger日志等级

    #这里进行判断,如果logger.handlers列表为空,则添加,否则,直接去写日志
    if not logger.handlers:
        #创建handler
        fh = logging.FileHandler("test.log",encoding="utf-8")
        ch = logging.StreamHandler()

        #设置输出日志格式
        formatter = logging.Formatter(
            fmt="%(asctime)s %(name)s %(filename)s %(message)s",
            datefmt="%Y/%m/%d %X"
            )

        #为handler指定输出格式
        fh.setFormatter(formatter)
        ch.setFormatter(formatter)

        #为logger添加的日志处理器
        logger.addHandler(fh)
        logger.addHandler(ch)

    return logger #直接返回logger

logger = log()
logger.warning("泰拳警告")
logger.info("提示")
logger.error("错误")
logger.debug("查错")

//导入包
import logging

logger = logging.getLogger()

#设置logger对象默认级别
logger.setLevel(logging.DEBUG)

#构建两个handler流
    #文件流对象
fh = logging.FileHandler("test.log",encoding="utf-8")
    #输出流对象
ch = logging.StreamHandler()


#将两个流设置给logger对象
logger.addHandler(fh)
logger.addHandler(ch)

#格式化
format1 = logging.Formatter(
    fmt="%(asctime)s %(name)s %(filename)s %(message)s",
    datefmt="%Y/%m%d %X"
)

format2 = logging.Formatter(
    fmt="%(asctime)s %(name)s ::: %(message)s",
    datefmt="%Y/%m%d %X"
)

#给输出流确定格式
fh.setFormatter(format1)
ch.setFormatter(format2)

#  使用logger对象进行日志记录
logger.debug("logger debug信息")
logger.info("logger info信息")
logger.warning("logger warning信息")
logger.error("logger error信息")
logger.critical("logger critical信息")


time时间模块

time 时间模块

三种时间形式。

时间戳, 
“年-月-日”  
时间元组(年,月,日)

时间几种形式转换

导入包

import time

time模块参数

time.strftime()
	以字符串展示时间

time.localtime()
	本地时间
	
time.gmtime()
	国标时间,国际标准时间

time.asctime([t])
	作用:将struct_time类型的时间转换为如下形式:'Sun Jun 20 23:21:05 1993'
	参数:struct_time类型或tuple类型的时间,不填参数的话默认为time.localtime()得到的时间。
	返回值:'Sun Jun 20 23:21:05 1993'类型的时间。

time.ctime([secs])
	作用:将时间戳的时间转换为表示本地时间的字符串。如果没有提供secs或没有提供secs,则使用time()返回的当前时间。
	参数:时间戳类型的时间,如果不填默认为当前时间的时间戳。
	返回值:格式化类型的时间,例如'Mon Mar 18 23:56:35 2019'。

time.sleep(secs)
	作用:在给定的秒数内挂起调用线程的执行。
	参数:秒数,参数可以是一个浮点数,表示更精确的睡眠时间。

查看时间

当前时间戳 float类型

import time
print(time.time())	#Unix开始时间到现在过了多少秒

当前时间字符串

print(time.strftime("%Y/%m%d %H:%M"))
print(time.strftime("%Y-%m-%d %X"))

当前时间元组

print(time.localtime())
print(type(time.localtime()))
t = time.localtime()
print(t[0])
print(t[1])

打印当前国标时间

print(time.gmtime())

时间转换

ret = time.localtime(3600*24)   #本地时间开始时间过1天后
gm = time.gmtime(3600*24)     #本地时间开始时间过1天后  3600s为1小时
print(ret)
print(gm)
print(3600/60/60)

ret2 = time.strftime("%Y-%m-%d %H:%M",ret)
print(ret2)
gm2 = time.strftime("%Y-%m-%d %H:%M",ret)
print(gm2)

print(time.asctime())
print(time.ctime())

datetime 时间模块

导入模块

import datetime

date类型

只限制到年月日

#格式化时间
import datetime
ret = datetime.date(2020,12,3)
print(ret)
print(type(ret))
print(ret.year)
print(ret.month)
print(ret.day)

time类型

仅限于时分秒

ret2 = datetime.time(12,23)
print(ret2)
print(ret2.hour)
print(ret2.minute)

datetime类型

包含年月日时分秒时间类型

ret3 = datetime.datetime(2020,12,13)
print(ret3)
print(type(ret3))

当前时间

now = datetime.datetime.now()
print(now)
print(now.year)
print(now.second)
print(now.strftime("%Y-%m-%d %X"))

strptime()时间类型转换

from datetime import datetime
first_date = datetime.strptime('2020-10-10','%Y-%m-%d')
print(first_date)

结果:
2020-10-10 00:00:00

timedelta类型

时间间隔,即两个时间点之间的长度

delta = datetime.timedelta(days=3)

now = datetime.datetime.now()
print(delta + now)  #输出三天后的日期是啊金
print((now - delta).strftime("%Y/%m/%d %X"))    #格式化输出3天前日期时间

s

实参 含义
%A 星期的名称
%B 月份名
%m 用数字表示的月份(01-12)
%d 用数字表示月份中的一天(01-31)
%Y 四位数的年份,如2020
%y 两位数的年份,如20
%H 24小时制的小时数(00-23)
%I 12小时制的小时数(01-12)
%p am或者pm
%M 分钟数(00-59)
%S 秒数 (00~60)

random 随机数模块

#导入包
from random import randint	

随机整数
n = randint(1,100)	#随机产生1-100的随机数
或者
 c_choice = random.randint(1,100)

random() 类型

随机浮点数

print(random.random())


randint() 类型

随机整数

print(random.randint(1,6))


choice() 类型

从序列元素中随机选取一个

print(random.choice([1,2,3,4]))


sample() 类型

从序列元素中随机选取n个

print(random.sample([1,2,3,4,5],2))


uniform() 类型

从元素中取随机浮点数

print(random.uniform(1,3))


shuffle() 类型

将顺序打乱

qq = [1,2,3,4,5,6,7]
random.shuffle(qq)
print(qq)

生成5位随机验证码

import random

def v_vode():

    code = ''
    for i in range(5):
        num = random.randint(0,9)           #生成0-9数字
        upper = chr(random.randint(65,90))      #生成A~Z字母
        lower = chr(random.randint(96,122))     #生成a~z字母
        code += random.choice([str(num),upper,lower])   #从序列中随机选取一个数
    return code

print(v_vode())

base64加密/解密

调用

import base64

关于Base64编码格式提供了以下六种接口,便于高效灵活地实现需要的编解码工作。

1. b64encode(s, altchars=None)
2. b64decode(s, altchars=None)
3. standard_b64encode(s)
4. standard_b64decode(s)
5. urlsafe_b64encode(s)
6. urlsafe_b64decode(s)

其中以"encode"结尾的方法用于将二进制串转为base64编码格式的字符串,以“decode”结尾的方法用于将base64格式的字符串重新转为二进制串。

  • 我们详细查看前两个方法,注意到b64encode()和b64decode()接收同样形式的参数。其中 s 是要编/解码的字符串;默认参数altchars的可选值必须是长度至少两字节的字符串(第二个字符后的内容将被忽略),该方法表示在编/解码过程中将使用参数altchars中的前两个字符替换标准Base64字符集中的'+'和'/'。

  • 因此方法3和4中的base64.standard_b64encode(s)和base64.standard_b64decode(s)等价于base64.b64encode(s)和base64.b64decode(s)。

  • 而方法5和6中的base64.urlsafe_b64encode(s)和base64.urlsafe_b64decode(s)分别等价于base64.b64encode(s , '-')和base64.b64decode(s , '-'),即在编/解码过程中使用'-'和'_'替代标准Base64字符集中的'+'和'/',生成可以在URL中使用的Base64格式文本。

  使用示例:

import base64

#将内容转换为二进制,base64编码
ll = "hello"
base = base64.b64encode(ll.encode())      
print(base)     #b'aGVsbG8='

#base64解码,然后二进制内容转换为文本
qq = base64.b64decode(base)
print(qq.decode())       #'hello'

本模块还提供了Base32和Base16编解码接口:  

Base16编解码:

qw = 's'
base = base64.b32encode(qw.encode())
print(base)     #b'OM======'

base = base64.b32decode(base)
print(base.decode())        #s

Base16编解码:

qw = 's'
base = base64.b16encode(qw.encode())
print(base)     #b'73'

base = base64.b16decode(base)
print(base.decode())        #s

遇见的报错问题

AttributeError: module 'hashlib' has no attribute 'md5' 报错

import hashlib
hd = hashlib.md5()
s1 = "li".encode()
hd.update(s1)
print(hd.hexdigest())

在练习hashlib 模块的时候,遇到的一个问题,因为敲的是跟课堂上一模一样的代码,然后百思不得其解,怀疑到python版本上来了,google发现问题的根源在于我的脚本文件命名与python内置模块重名导致的。

原因

python在执行程序的时候,会先将当前目录下的hashlib导入,正好是我取得文件名是hashlib。程序会将我创建的hashlib导入进入,而找不到里面定义的功能模块,所以会报错

标签:logging,模块,print,path,日志,os
From: https://www.cnblogs.com/megshuai/p/18517563

相关文章

  • mcu程序中的存储模块
    硬件知识基于成本与需求的考虑,铁电已经很少使用,最常用的是eeprom与flasheeprom相对于flash的优势是寿命长(100万次1万次),且可以按字节操作所以一般嵌入式系统中eeprom存储运行时参数(掉电需保存的参数或者频繁需要修改的数据),flash存储写次数较少但数据量较大的数据(日志......
  • 服务器漏洞修复和php一键安装包环境 nginx 安装拓展模块
    服务器漏洞修复header头缺失问题https://blog.51cto.com/u_16213703/10249280add_headerX-XSS-Protection'1;mode=block';add_headerX-Frame-OptionsSAMEORIGIN;add_headerX-Content-Type-Optionsnosniff;add_headerX-Download-Options:noopen;......
  • 在 Odoo 中,确实可以通过 SQL 语句来提升一些功能逻辑的处理效率。将 SQL 转为 Python
    1.使用env.cr.execute执行SQL语句OdooORM提供的env.cr.execute()可以直接执行SQL语句,这样可以在Python代码中调用SQL逻辑,结合Odoo的业务模型实现复杂的逻辑操作。execute()方法适合处理批量数据更新、复杂查询等。示例:批量更新customer_id字段defupdate_......
  • Python 进度条模块tqdm
    1.简介在处理大规模数据或长时间运行的任务时,了解任务的进度对于用户体验和调试来说非常重要。tqdm是一个用于显示进度条的Python库,它能将任务的进度信息直观地展示出来。无论是遍历一个大型列表、处理批量数据,还是下载文件,tqdm都能轻松实现进度条显示,并且与Python的标准......
  • (ICCV2023)多尺度空间特征提取模块,有效涨点,即插即用
    题目:SAFMN:Spatially-AdaptiveFeatureModulationforEfficientImageSuper-Resolution期刊:CVPR(ConferenceonComputerVisionandPatternRecognition)GitHub地址:https://github.com/sunny2109/SAFMN年份:2023作者单位:TheChineseUniversityofHongKong(CUHK)......
  • Python 标准库——argparse模块
    文章目录前言一、主要作用二、基本步骤1.导入模块2.创建解析器对象3.添加参数4.解析参数5.使用解析后的参数6.编写主函数并调用三、函数示例前言argparse是Python标准库中的一个模块,用于编写用户友好的命令行接口。它允许你轻松地定义程序应该接受的命令行参数,并......
  • D53【python 接口自动化学习】- python基础之模块与标准库
    day53自定义模块学习日期:20241030学习目标:模块与标准库--67自定义模块:如何编写一个完整功能?学习笔记:创建自定义模块自定义模块注意事项 自定义模块deffunc1():return'thisisafunction'classClass1(object):def__init__(self):print(......
  • Python包和模块
    Python包和模块当使用Python编程时,包(Packages)和模块(Modules)是两个关键的概念,它们有助于组织、管理和复用代码。1.模块(Modules)1.1什么是模块一个.py文件就是一个模块模块是含有一系列数据,函数,类等的程序作用把相关功能的函数等放在一起有利于管理,有利于多人合作开......
  • 正向代理模块实现
    1概念1.1正向代理概念正向代理是一个位于客户端和目标服务器之间的代理服务器(中间服务器)。为了从目标服务器取得内容,客户端向代理服务器发送一个请求,并且指定目标服务器,之后代理向目标服务器转发请求,将获得的内容返回给客户端。正向代理的情况下,客户端必须要进行一些特殊的......
  • GE通用模块DS200SBCBG1ADC的优缺点
    通用电气GE的DS200SBCBG1ADC模块作为一款高性能的处理器板,具有一系列显著的优点,同时也存在一些潜在的缺点。以下是对该模块优缺点的详细分析:优点高精度模拟输出:DS200SBCBG1ADC模块提供12位模拟输出,这意味着它能够以更高的精度控制信号,从而满足对精度要求较高的工业自动化......