当前位置: 首页 > news >正文

Python 模块和包

1. 模块和包

  • **容器:**列表、元组、字符串、字典等,对数据的封装
  • **函数:**对语句的封装
  • **类:**对方法和属性的封装,即对函数和数据的封装

而模块(module)就是个程序,一个.py 文件,模块分为三类:

  • **Python 标准库:**如 time、random 等
  • **第三方模块:**如 requests、beautiful 等
  • **应用程序自定义模块:**用户自定义模块

随机程序代码越写越多,每个文件里面的代码越来越长,越来越不容易维护。使用模块的好处:

  • 模块化代码: 将不同功能的代码归类,提高代码的可维护性
  • **避免重复造轮子:**编写代码可以不必从零开始,可以引用别人已经写好的模块,Python 有很多优秀的第三方模块
  • **命名空间:**每个模块单独维护一个命名空间,不同模块相同函数名、变量名不会有冲突

**Tips:**自定义模块的时候,不要与内置的模块名有冲突,不然会影响内置模块

1.1 包

为了避免不同的人编写的模块名相同,Python 引入了按目录来组织模块的方法 —— 包(Package)

不同包下的模块,名字相同不会有冲突,只要顶层的包名不冲突就行。

如何创建一个包:

  • 创建一个文件夹,里面存放相应模块文件,文件夹名字即为包名
  • 在文件夹中创建一个 __init__.py 文件,可以为空

1.2 导入模块

导入模块的几种常用方法:

>>> import 模块1, 模块2...		# sys.path:搜索路径>>> from 模块名 import 函数名>>> from 模块名 import *	# 导入模块中所有函数,不推荐,导致命名空间优势荡然无存from one.two import main>>> import 模块名 as newname		# 当模块名比较长时,我们可以给它去个新名字,使用起来更方面

导入模块后,就需要使用模块中的函数,我们可以使用 模块名.函数名 或直接调用函数即可:

# calc.py
def add(x, y):return x + y
import calc			# 导入模块,使用 模块名.函数名 的方法调用函数
calc.add(4, 6)from calc import add		# 直接把函数名也导入,可以直接调用函数
add(4, 6)

不同包中的模块导入方法

three.py 是个模块,two 是个包,两者同级。要想在 three.py 中导入 calc.py

from one.two import calc

1.3 __name__ == '__main__'

有时我们在阅读别人的源代码时,经常看到代码中有 if __name__ == '__main__',它有什么作用呢?

  • **在被调用文件上:**用于被调用文件的测试
  • 在执行文件上: 不想这个文件成为被调用文件
# calc.py
pi = 3.14def main():print('pi:', pi)
main()

现在我们想在bin.py 中,调用 cacl.py 中的 add()函数计算两个数的和:

# bin.py
from calc import pidef calc_round_area(radius):return pi * (radius ** 2)def main():print('round area:', calc_round_area(2))main()
pi: 3.14
round area: 12.56

bin.pymain()函数也执行了,而不是我们想要的只执行calc_round_area() 函数。在有些时候我们只想 被调用模块的部分程序(函数)被调用,而不是全部程序。我们可以在 被调用模块中添加 if __name__ == '__main__',将不想被调用的函数放入里面即可,能被调用的不放入其中(开发相应的接口即可)。

# calc.py
pi = 3.14def main():print('pi:', pi)if __name__ == '__main__':main()
from calc import pidef calc_round_area(radius):return pi * (radius ** 2)def main():print('round area:', calc_round_area(2))main()

我们再执行 bin.py, 发现只执行:

round area: 12.56

函数也是对象,每个对象都有一个__name__ 属性,在程序中,我们查看__name__ 属性为 '__main__',因此为 True:

# calc.py
....
print(__name__)'__main__'

一旦我们引入到其他模块中,__name__ 属性就变成了 被引入模块的路径,而不再是 __main__,因此为 False,即不能执行被调用模块 if __name__ == '__main__' 的程序。

# bin.py
...
print(calc.__name__)'calc'

另一个作用是不想这个模块文件称为被调用文件,我们将所有的调用方式都放入__name__==__main__下,没有开发接口,别人就不能调用模块中的任何函数了。

1.4 搜索路径

模块是一个 .py 文件,那么必然有个路径。每次导入模块时,首先在内置在解释器中找是否有这个模块(如:sys、time 模块),再搜索安装目录。下载安装的模块一般都是在 Python 安装路径下的 Lib 目录下,也可以使用 sys.path 查看:

import sys
sys.path['', 'C:\\Users\\HJ\\Anaconda3\\python36.zip', 'C:\\Users\\HJ\\Anaconda3\\DLLs', 'C:\\Users\\HJ\\Anaconda3\\lib', 'C:\\Users\\HJ\\Anaconda3', 'C:\\Users\\HJ\\Anaconda3\\lib\\site-packages', 'C:\\Users\\HJ\\Anaconda3\\lib\\site-packages\\win32', 'C:\\Users\\HJ\\Anaconda3\\lib\\site-packages\\win32\\lib', 'C:\\Users\\HJ\\Anaconda3\\lib\\site-packages\\Pythonwin']

对于自定义的模块,可以使用 sys 模块将其路径添加到 sys.path 中,需要注意的是,这是临时修改,永久修改需要修改系统环境变量。

sys.path.append('C:\\Python36\\test\\')

BASE_DIR

每次这样将绝对路径添加到 sys.path 中,一旦将程序拷贝别人使用,就会出现没有这个模块的问题,我们可以借用 BASE_DIR 来将文件本身的路径添加到 sys.path 中。

# __file__ :拿到文件名,在 Pycharm 中之所以看到的是绝对路径,是 Pycharm 给我们自动添加的
# os.path.abspath(__file__) 可以拿到文件的绝对路径
import sys, osBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)

2. 模块

2.1 time 模块

Python 中三种时间表示法:

  • **时间戳(timestamp):**时间戳是从 1970年1月1日 00:00:00 开始按秒计算的偏移量,返回的是浮点型
  • **结构化时间(struct_time):**共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
  • **格式化的时间字符串:**格式化后的时间,如 1970-1-1 00:00:00
import time
# 1. time():返回当前时间的时间戳
>>> time.time()
1542195047.3042223# 2. localtime([secs]):将一个时间戳转换为当前时区的结构化时间,未指定时间戳则以当前时间为准
>>> time.localtime()		# 查看当前时间的结构化时间
time.struct_time(tm_year=2018, tm_mon=11, tm_mday=14, tm_hour=19, tm_min=32, tm_sec=51, tm_wday=2, tm_yday=318, tm_isdst=0)
>>> time.localtime(1432195047.3042223)		# 传入时间戳,查看某个时间的结构化时间
time.struct_time(tm_year=2015, tm_mon=5, tm_mday=21, tm_hour=15, tm_min=57, tm_sec=27, tm_wday=3, tm_yday=141, tm_isdst=0)# 3. gmtime([secs]):与 localtime()类似,将一个时间戳转换为UTC时区(0时区)的struct_time。时间标准时间
# UTC:英国格林威治,全球每 15 度为一个时区,总共 24 个时区,格林威治为时间标准时间,中国为东八区,也就是说中国要比时间标准时间早八个小时
>>> time.gmtime()			# 比中国晚早 8 小时
time.struct_time(tm_year=2018, tm_mon=11, tm_mday=14, tm_hour=11, tm_min=34, tm_sec=50, tm_wday=2, tm_yday=318, tm_isdst=0)# 4. mktime(p_tuple):将结构化时间转换为时间戳,参数为结构化的时间
>>> time.mktime(time.localtime())	# 将当前时间的结构化时间转换为时间戳
1542195406.0# 5. strftime(format[, t]):将结构化时间转换为字符串时间,第一个参数为格式化成的时间格式,第二个为结构化时间, %X 表示时分秒,中间的分隔符随意
>>> time.strftime('%Y-%m-%d %X', time.localtime())		# 将当前时间的结构化时间转换为字符串时间
'2018-11-14 19:39:22'# 6. strptime(string,format):将一个格式化时间字符串转换为结构化时间,与 strftime()是逆操作
>>> time.strptime('2018:11:14:19:42:56', '%Y:%m:%d:%X')
time.struct_time(tm_year=2018, tm_mon=11, tm_mday=14, tm_hour=19, tm_min=42, tm_sec=56, tm_wday=2, tm_yday=318, tm_isdst=-1)# 7. asctime([t]):将结构化时间转换为一个固定形式的字符串时间,默认为 time.localtime()
>>> time.asctime()
'Wed Nov 14 19:45:57 2018'# 8. ctime([secs]):将时间戳转换为一个固定形式的字符串时间,默认为 time.time()
>>> time.ctime()
'Wed Nov 14 19:46:07 2018'
>>> time.ctime(1542195047.3042223)
'Wed Nov 14 19:30:47 2018'# 9. sleep(secs):线程推迟指定的时间运行,单位为秒
>>> time.sleep(3)# 10. clock():不同系统上含义不同,UNIX 系统上,返回的是 “进程时间”。Windows 系统上,第一次调用为进程运行实际时间,第二次调用为第一次调用到现在的运行时间,即两次调用的时间差。
>>> time.clock()

datetime 模块

datetime 模块也是一个时间模块,只需记得一些一个方法即可:

import datetimeprint(datetime.datetime.now())		# 查看当前时间的结构化时间
2018-11-14 16:56:12.065709

2.2 random 模块

随机模块,产生一个随机数

import random# 1. random():随机产生一个 0 ~ 1 的浮点数
>>> random.random()
0.42091646162129426# 2. randint(start, stop):产生一个 start ~ stop 的随机整数,包含左右 [start, stop]
>>> random.randint(1, 3)
2# 3. randrange(start,stop[,step]): 产生一个指定递增基础集合中的一个随机整数,基数缺省为 1 ,[start, stop)
>>> random.randrange(10, 20, 2)		# 返回 [10, 20) 间的偶数
18
>>> random.randrange(10, 20, 3)		# 返回 [10, 20) 间的其他数
13
>>> random.randrange(10, 20)		# 返回 [10, 20) 间的任意一个数
17# 4. choice(seq):在一个序列中随机获取一个元素
>>> random.choice([1, 2, 3])
2
>>> random.choice('hello')
'l'# 5. sample(seq, k):从指定序列中随机获取指定长度 的片段,不会修改原有序列
>>> random.sample([1, 2, 3, 4], 2)		# 获取两个元素
[2, 3]# 6. uniform(start,stop):随机产生一个 start ~ stop 范围的浮点数
>>> random.uniform(1, 3)
2.4704091068940937# 7. shuffle(seq):打乱列表中元素顺序
>>> n = [1, 2, 3]
>>> random.shuffle(n)
>>> n
[1, 3, 2]

随机验证码生成:

import randomdef v_code():"""产生一个四个字符组成的随机验证码:return: 验证码"""res = ''for i in range(4):num = random.randint(0, 9)      # 产生一个 0~9 的随机整数alf = chr(random.randint(65, 90))    # 产生一个 65~90 的随机整数,再用 chr()转换为大写字母ret = random.choice([num, alf])        # 从 num、alf 中随机选取一个res += str(ret)return resres = v_code()
print(res)S3H6

2.3 os 模块

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

import os
# getcwd():获取当前工作目录
>>> os.getcwd()
'E:\\电脑软件\\cmder'# chdir(path):改变当前工作目录,支持绝对路径和相对路径
>>> os.chdir('..')		# 返回上一层目录
>>> os.chidr('E:\\')
>>> os.getcwd()
E:\\# listdir(path='.'):列出指定目录下所有文件和目录
>>> os.listdir()
['.ipynb_checkpoints', 'bin', 'Cmder.exe', 'config', 'icons', 'LICENSE', 'README.md', 'SUMMARY.md', 'Untitled.ipynb', 'vendor', 'Version 1.3.6.678']
>>> os.listdir('E:\\')# mkdir(path):创建文件夹,若该文件夹存在,抛出 FileExistsError 异常
>>> os.mkdir('test')# makedirs(path):创建多层目录
>>> os.makedirs('dir1/dir2')		# 适用 Linux 和 win
>>> os.makedirs(r'E:\a\b\c')		# 仅适用 win# remove(path):删除指定文件,不能删除目录
>>> os.remove(r'E:\a\b\c\a.txt')# rmdir('dir'):删除单个目录,若目录为空,则无法删除
>>> os.rmdir(r'E:\a\b\c')# removedirs(path):若目录为空,则删除。并递归到上一级目录,如若也为空,则删除,依次类推
>>> os.removedirs(r'E:\a\b')# rename(old,new):重命名文件或文件夹
>>> os.chdir(r'E:\\')
>>> os.getcwd()
'E:\\'
>>> os.mkdir('a')
>>> os.rename('a', 'b')# system("bash command")  运行shell命令,直接显示
>>> os.system('calc')		# 调用系统内置计算器# stat('path/filename'):查看文件/目录信息(如:创建时间、修改时间、字节等)
# st_size=7:文件多少个字节、st_atime:用户上一次的访问时间、st_mtime:上一次修改的时间、st_ctime:创建时间
>>> os.stat(r'E:\b\a.txt')
os.stat_result(st_mode=33206, st_ino=1125899906882595, st_dev=646140012, st_nlink=1, st_uid=0, st_gid=0, st_size=7, st_atime=1542207918, st_mtime=1542207963, st_ctime=1542207918)# sep:输出当前操作系统特定的路径分隔符,win 下为 \\,Linux 为 /
>>> os.sep
'\\'# linesep:输出当前平台使用的行终止符,win下为 \r\n,Linux 下为 \n
>>> os.linesep
'\r\n'# pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为
>>> os.pathsep
';'# name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
>>> os.name
'nt'# environ  获取系统环境变量
>>> os.envirom# curdir:返回当前目录:(.)
>>> os.curdir
'.'# pardir:获取当前目录的父目录字符串名:(..)
>>> os.pardir
'..'# walk(path):返回指定路径下所有子目录,结果是一个三元组(路径,[包含目录],[包含文件])
>>> for i in os.walk(r'E:\b'):
...     print(i)
...
('E:\\b', [], ['a.txt'])

os.path 模块

import os
# abspath(path):返回文件或目录规范化的绝对路径
>>> os.path.abspath('a.txt')
'E:\\b\\a.txt'# split(path):将 path 分割成目录和文件名二元组返回
>>> os.path.split(r'E:\b\a.txt')
('E:\\b', 'a.txt')
>>> os.path.split(os.path.abspath('a.txt'))
('E:\\b', 'a.txt')# splitext(path):分割文件拓展名
>>> os.path.splitext(os.path.abspath('a.txt'))
('E:\\b\\a', '.txt')# dirname(path):去掉文件名,返回目录,即返回 os.path.split[0]
>>> os.path.dirname(r'E:\b\a.txt')
'E:\\b'# basename(path):去掉目录,返回文件名,即返回 os.path.split[1]
>>> os.path.basename(r'E:\b\a.txt')
'a.txt'# exists(path):如果 path 存在,返回 true,否则为 false
>>> os.path.exists(r'E:\b')
True# isabs(path):如果 path 是绝对路径,返回 true,否则为 false
>>> os.path.isabs(r'E:\b')
True# isfile(path):判断指定路径是否存在且是一个文件
>>> os.path.isfile(r'E:\b')
False# isdir(path):判断指定路径是否存在且是一个目录
>>> os.path.isdir(r'E:\b')
True# join(path1[, path2[,...]]):拼接多个路径,第一个绝对路径之前的参数将被忽略
>>> a = r'E:\a\b'		
>>> b = r'c\a.txt'		# 相对路径
>>> os.path.join(a, b)
'E:\\a\\b\\c\\a.txt'>>> a = r'E:\a\b'		
>>> b = r'F:\c\a.txt'		# 第一个绝对路径之前的参数将被忽略
>>> os.path.join(a, b)
'F:\\c\\a.txt'>>> a = r'E:\a\b'		
>>> b = r'E:\d\a.txt'		# 第一个绝对路径之前的参数将被忽略
>>> os.path.join(a, b)
'E:\\d\\a.txt'# getatime(path):返回 path 所指向的文件或目录的最后存取时间
>>> os.path.getatime(r'E:\b\a.txt')
1542207918.4124079# getmtime(path):返回 path 所指向的文件或目录的最后修改时间
>>> os.path.getmtime(r'E:\b\a.txt')
1542207963.2649732# getctime(path):返回 path 所指向的文件或目录的创建时间
>>> os.path.getctime(r'E:\b\a.txt')
1542207918.4124079# getsize(path):返回 path 所指向的文件或目录的大小(字节)
>>> os.path.getsize(r'E:\b\a.txt')
7

图片爬取全代码:

# 图片爬取全代码
import requests
import osurl = 'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2079998410,926856509&fm=26&gp=0.jpg'
root = r'E:\\pics\\'
path = root + url.split('/')[-1]try:if not os.path.exists(root):      # 目录不存在,则新建os.mkdir(root)if not os.path.exists(path):     # path 不存在就爬取,存在就打印 文件已经存在r = requests.get(url)with open(path, 'wb') as f:f.write(r.content)f.close()print('保存文件成功')else:print('文件已经存在')
except:print('爬取失败')

2.4 sys 模块

import sys
# exit(n):退出程序,正常退出是 exit(0)
>>> exit(0)attempt to call a nil value
# version:获取 Python 解释器程序的版本信息
>>> sys.version
'3.6.5 |Anaconda, Inc.| (default, Mar 29 2018, 13:32:41) [MSC v.1900 64 bit (AMD64)]'# path:返回模块的搜索路径,初始化时使用 PythonPath 环境变量的值
>>> sys.path# platform:返回操作系统平台名称
>>> sys.platform
'win32'

argv 变量

argv 命令行参数 List,第一个元素是程序本身路径,如允许 python hello.py 获得的 sys.argv 就是 ['hello.py'],允许 python hello.py poost 获得的 sys.argv 就是 ['hello.py', 'post']

# hello.py
#!/usr/bin/env python3			# 任何平台都能使用
# -*- coding: utf-8 -*- 		# 编码格式
'一个测试 avgv 变量的模块'
__author__ = 'Hubery_Jun'import sysdef test():args = sys.argvif len(args) == 1:print('Hello, world')elif len(args) == 2:print('Hello, %s' % args[1])else:print('Too many arguments')if __name__ == '__main__':test()

在命令行运行 hello.py

$ E:\PycharmProjects\university_test\day21\one\four>python shenzhen_work.py
Hello, world$ E:\PycharmProjects\university_test\day21\one\four>python shenzhen_work.py rose
Hello, rose

Python shell 交互环境中:

>>> import hello
>>> hello.test()
Hello world

FTP 上传下载功能简单实现

# ftp.py
import sysdef test():command = sys.argv[1]path = sys.argv[2]# 上传if command == 'post':print('post 请求方式')# 下载elif command == 'get':print('get 请求方式')print('下载路径为 %s' % path)if __name__ == '__main__':test()

命令行中运行 ftp.py

$ python ftp.py get E:/download/
get 请求方式
下载路径为 E:/download/

进度条实现

import time
import sysfor i in range(20):sys.stdout.write('#')time.sleep(0.1)sys.stdout.flush()

2.5 json 模块

之前我们学过 eval 方法可以将一个字符串处理成 Python 对象,对于普通的数据类型,eval 可以处理,但是对于特殊的数据了新,eval 就不管用了。json 适用于任何语言的数据交互,写入文件的必须是字符串类型。

序列化

把对象(变量)从内存中变成可存储或传输的过程称为 序列化,也叫 pickling,其他语言中称之为 serialization,marshalling,flattening等。反过来把变量内容从序列化的对象重新读取到内存中称之为 反序列化,即 unpickling

json

为了在不同编程语言之间能够互相传输,就必须把对象序列化为标准格式,如:XML,但最好的是 JSON。因为 json 表示出来的就是一个字符串,可以被任何语言读取,也方便存储到磁盘或通过网络传输,而且比 XML 更快,更可以在 Web 页面上读取,非常方便。

json 表示的对象就是标准的 JavaScript 语言的对象,json 和 Python 内置的数据类型对应关系如下:

json 类型Python 类型json 类型Python 类型
{}dict[]list
‘string’str1234.56int 或 float
true/falsetrue/falsenullNone
# 序列化
import jsondic = {'name': 'rose', 'age': 18}		# type(dic) 为 <class 'dict'>dic_sec = json.dumps(dic)		# 将 Python 的数据类型转换为 json (字符串)数据类型,type(dic_sec) 为 <class 'str'>f = open('test.json', 'w')		
f.write(dic_sec)		# 将 json 数据写入一个文件中
f.close()# dic_sec = json.dumps(dic)
# f.write(dic_sec)
# 等价于  json.dump(dic, f)
# 反序列化
import json
f = open('test.json', 'r')
data = json.loads(f.read())			#  等价于 data = json.load(f)
f.close()
type(data)		# <class 'dict'>

Tips:json 字符串是双引号,不认单引号。无论数据是怎样创建的,只要满足 json 格式(即双引号),就可以json.loads出来,不一定非要 dumps的数据才能 loads

2.6 pickle 模块

pickle 模块与 json 模块类似,用法一致,去区别在于 pickle 模块将数据序列化为 字节型,而 json 序列化为 字符串型

pickle 只能用于 Python,而且版本不同也有可能不同,因此只能用来保存不那么重要的数据。支持函数、类。

# 序列化
import pickledic = {'name': 'rose', 'age': 18}
dic_str = pickle.dumps(dic)		<class 'bytes'>
f = open('text.pkl', 'wb')		
f.write(dic_str)			# pickle.dump(dic, f)
f.close()
# 反序列化
import picklef = open('text.pkl', 'rb')
data = pickle.loads(f.read())			# data = pickle.load(f)
print(data)
f.close()

2.7 shelve 模块

与 json、pickle 类似,也是用于数据传输。只有一个open函数,返回类似字典的对象,可读可写 key 必须为字符串,而值可以是 python 所支持的数据类型。

import shelvef = shelve.open(r'shelve.txt')# 存储(会产生三个文件:xxx.bak、xxx.dat、xxx.dir)
# f['info'] = {'name': 'rose', 'age': 18}   # f 相当于一个空字典,写操作相当于给字典赋值
# f.close()print(f.get('info')['name'])        # 读取操作(类似于字典取值)----------------------------------------------------------
rose

2.8 XML 模块

xml 是实现不同语言或程序之间进行数据交换的协议,跟 json 差不多,但 json 使用起来更简单。xml 比 json 出现更早,早前不同语言之间数据交换都是 xml,现在仍然有很多公司、语言在用,但 json 是未来趋势。

import xml.etree.ElementTree as et
tree = et.parse('test.xml')			# 解析 text.xml 
root = tree.getroot()		# 获取根节点
# node.tag:获取标签名
# node.attrib:获取属性名
# node.text:获取文本内容
# root.findall('node_name')			查看根节点下所有叫 node_name 的标签
# node.find('node_name')			查看某个标签下某个子标签(子节点)
# root.iter('node_name')			查看根节点下所有叫 node_name 的标签
# node.set('属性名', '属性值')		修改某个节点的属性
# root.remove('node_name')			删除某个节点
# tree.write('text.xml')			不管是删除还是修改都要将修改后的文件写入原文件中
  • findall:查找的是所有某个节点
  • find:查找某个节点,当有多个时,只返回第一个
country = root.find('country')
print(country.tag, country.attrib)rank = country.find('rank')
print(rank.tag, rank.attrib, rank.text)
country {'name': 'Liechtenstein'}
rank {'updated': 'yes'} 2

XML 文档操作

<?xml version="1.0"?>
<data><country name="Liechtenstein"><rank updated="yes">2</rank><year>2008</year><gdppc>141100</gdppc><neighbor name="Austria" direction="E"/><neighbor name="Switzerland" direction="W"/></country><country name="Singapore"><rank updated="yes">5</rank><year>2011</year><gdppc>59900</gdppc><neighbor name="Malaysia" direction="N"/></country><country name="Panama"><rank updated="yes">69</rank><year>2011</year><gdppc>13600</gdppc><neighbor name="Costa Rica" direction="W"/><neighbor name="Colombia" direction="E"/></country>
</data>
import xml.etree.ElementTree as ettree = et.parse('test')        # 解析(读取)root = tree.getroot()       # 获取根节点# print(root.tag)         # 打印根节点名称# 遍历 xml 文档
# for country in root:
#     # print(country.tag, country.attrib)
#     for i in country:
#         print(i.tag, i.text)# # 只遍历所有 year 节点
# for year in root.iter('year'):
#     print(year.tag, year.text)# # 修改
# for year in root.iter('year'):
#     new_year = int(year.text) + 3
#     year_text = str(new_year)
#     year.set('updated', 'yes')
# tree.write('test')# # 删除
# for country in root.findall('country'):
#     rank = int(country.find('rank').text)
#     if rank > 50:
#         root.remove(country)
# tree.write('test')

生成 xml 文档

使用 Python 也可以手动生成 xml 文档。

import xml.etree.ElementTree as et
new_xml = et.Element('root_node')	# 创建一个名为 root_node 的根节点
node = et.SubElemnt(father_node, node, attrib={'key': 'value'})		# 创建一个名为 node 的结点,父节点为 father_node
node.text = 'value'		# 设置某个节点的文本内容
ts = et.ElementTree(new_xml)		# 生成文档树对象
ts.write('test.xml', encoding='uft-8', xml_declaration=True)et.dump(new_xml)	# 打印生成的格式
import xml.etree.ElementTree as etnew_xml = et.Element('data')		# 生成一个名叫 data 的根节点
name = et.SubElement(new_xml, 'name', attrib={'enrolled': 'yes'})	# 创建一个 name 节点,父节点为 new_xml 即 data
age = et.SubElement(name, 'age', attrib={'checked': 'no'})	# 创建一个 age 节点,父节点为 name
sex = et.SubElement(name, 'sex')
sex.text = '33'ts = et.ElementTree(new_xml)		# 生成文档树对象
ts.write('test.xml', encoding='uft-8', xml_declaration=True)et.dump(new_xml)	# 打印生成的格式

生成的 xml 文档:

<!--test.xml-->
<?xml version='1.0' encoding='utf-8'?>
<data><name enrolled="yes"><age checked="no" /><sex>33</sex></name>
</data>

2.9 logging 模块

logging 模块将日志打印到标准输出中,且只显示大于等于 WARNING 级别的日志,默认日志级别为 WARING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),默认的日志格式为日志级别:Logger名称:用户输出消息。

logging 模块有两种输出日志的方法:第一是利用 basicConfig 函数进行相应的配置,第二是 logger 对象输出。

2.9.1 basicConfig 函数

basicConfig() 函数有很多参数,通过更改其中参数可来设定日志输出形式以及格式等,具体参数如下:

  • filename:用指定的文件名创建 FileHandle ,这样日志会被存储到指定的文件中。
  • filemode:文件打开方式,在指定了 filename 后,默认为 :‘a’(追加),可以指定为 ‘w’(覆盖)
  • format:指定 handle 使用的日志显示格式
  • datefmt:指定日期时间格式
  • level:设置 rootlogger 的日志级别
  • stream:用指定的 stream 创建 StreamHandle。可以指定输出到 sys.stderr,sys,stdout(输出到屏幕)或文件f=open('test.log', 'w')(输出到文件中),默认为输出到屏幕。若同时列出了 filename 和 stream 两个参数,则 stream 参数会被忽略。

Format 参数中可能用到的格式化串:

  • %(name)s :Logger的名字
  • %(levelno)s :数字形式的日志级别
  • %(levelname)s :文本形式的日志级别
  • %(pathname)s :调用日志输出函数的模块的完整路径名,可能没有
  • %(filename)s :调用日志输出函数的模块的文件名
  • %(module)s :调用日志输出函数的模块名
  • %(funcName)s :调用日志输出函数的函数名
  • %(lineno)d :调用日志输出函数的语句所在的代码行
  • %(created)f :当前时间,用UNIX标准的表示时间的浮 点数表示
  • %(relativeCreated)d :输出日志信息时的,自Logger创建以 来的毫秒数
  • %(asctime)s :字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
  • %(thread)d :线程ID。可能没有
  • %(threadName)s :线程名。可能没有
  • %(process)d :进程ID。可能没有
  • %(message)s:用户输出的消息

示例:

import logginglogging.basicConfig(level=logging.DEBUG,# 当前时间,模块名,行号,等级名,输出信息format='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s',#datefmt='%a, %d %b %Y %H:%M:%S',#filename='test.log')
logging.debug('debug message')
logging.info('info message')
logging.warning('waring message')
logging.error('error message')
logging.critical('critical message')

输出:

2018-11-19 17:04:06,070 logging_test.py [line:10] DEBUG debug message
2018-11-19 17:04:06,071 logging_test.py [line:11] INFO info message
2018-11-19 17:04:06,071 logging_test.py [line:12] WARNING waring message
2018-11-19 17:04:06,071 logging_test.py [line:13] ERROR error message
2018-11-19 17:04:06,071 logging_test.py [line:14] CRITICAL critical message

basicConfig() 函数配置日志不够灵活,而且不能同时输出在屏幕的同时,保存到文件,而 logger 对象恰好可以解决。

2.9.2 logger 对象

logging.basicConfig() 用默认日志格式(Format)为日志系统建立一个默认的流处理器(StreamHandler),设置基础配置(如日志级别等)并加到 root logger(根 Logger中)这几个 logging 模块级别的函数。另一个模块级别的函数 logging.getLogger([name]) 返回一个 logger 对象,如果没有指定名字将返回 root logger。

一个 logger 对象:

import logginglogger = logging.getLogger()		# 创建一个 logger 对象
#logger.setLevel('DEBUG')			设定日志等级fh = logging.FileHandler('log.log')		# 创建一个 handle,用于写入日志文件ch = logging.StreamHandler()		# 创建一个 handle,用于输出到屏幕# 指定日志显示格式
fomatter = logging.Formatter('%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s %(message)s')# logger 对象添加多个 fh、ch 对象(既输出到文件中,也输出到屏幕上)
logger.addHandler(fh)
logger.addHandler(ch)# 各等级日志输出信息
logger.debug('debug message')
logger.info('info message')
logger.warning('waring message')
logger.error('error message')
logger.critical('critical message')
waring message
error message
critical message

默认只输出三个级别,可以通过 logger.setLevel('DEBUG') 设定日志级别。可用的日志级别有logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL

logging 库提供了多个组件:

  • **Logger:**Logger 对象
  • **Handler:**发送日志到文件中或屏幕上
  • **Filter:**过滤日志信息
  • **Format:**指定日志显示格式

Logger 对象提供了应用程序可直接使用的接口,Logger 是一个树形层级结构,输出信息之前要获得一个 Looger 对象(如果没有指定名字,那么就是 root Looger 根)。

两个 logger 对象

logger1 = logging.getLogger('mylogger')
logger2 = logging.getLogger('mylogger')logger1.setLevel(logging.DEBUG)
logger2.setLevel(logging.INFO)fh = logging.FileHandler('new_log.log')
ch = logging.StreamHandler()logger1.addHandler(fh)
logger1.addHandler(ch)logger2.addHandler(fh)
logger2.addHandler(ch)logger1.debug('debug message')
logger1.info('info message')
logger1.warning('waring message')
logger1.error('error message')
logger1.critical('critical message')logger2.debug('debug message')
logger2.info('info message')
logger2.warning('waring message')
logger2.error('error message')
logger2.critical('critical message')
info message
waring message
error message
critical message
info message
waring message
error message
critical message

可以看出输出了两次从 INFO 级别开始的日志,导致出现这种情况出现的原因有两个:

  • logger1 和 logger2 两个所创建的对象对应的是同一个 Logger 实例(只要 logging.getLogger(name) 中的 name 相同,则就是同一个实例,有且仅有一个)。在 logger2 实例中将 mylogger 的日志级别设置为 logging.INFO,所有遵从了后来设置的日志级别。

对于上述情况,我们只需设置不同的 name 即可。

一个 logger 和 一个 logger1 对象

# 一个 logger 和 一个 logger1 对象
logger = logging.getLogger()
logger.setLevel(logging.INFO)logger1 = logging.getLogger('mylogger')
logger1.setLevel(logging.DEBUG)ch = logging.StreamHandler()logger.addHandler(ch)
logger1.addHandler(ch)logger.debug('debug message')
logger.info('info message')
logger.warning('waring message')
logger.error('error message')
logger.critical('critical message')logger1.debug('debug message')
logger1.info('info message')
logger1.warning('waring message')
logger1.error('error message')
logger1.critical('critical message')
info message
waring message
error message
critical message
debug message
debug message
info message
info message
waring message
waring message
error message
error message
critical message
critical message

之所以会出现两次,是因为我们通过 logger = logging.getLogger()显示的创建了root Logger,而logger1 = logging.getLogger('mylogger')创建了root Logger的孩子(root.)mylogger,logger2。而子孙既会将消息发布给给它的 Handler 处理,也会传递给它的祖先 Logger 处理。

只要将 logger 输出注释掉就行 # logger.addHandler(ch)

Filter

import logginglogger = logging.getLogger()
logger1 = logging.getLogger('mylogger')# 输出到屏幕(控制台)
ch = logging.StreamHandler()# 定义一个 filter
f = logging.Filter('mylogger')
ch.addFilter(f)logger.addHandler(ch)
logger1.addHandler(ch)# # 设置等级
# logger.setLevel(logging.DEBUG)
# logger1.setLevel(logging.DEBUG)logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')logger1.debug('1')
logger1.info('2')
logger1.warning('3')
logger1.error('4')
logger1.critical('5')
3
3
4
4
5
5

2.10 configparser 模块

可以用来生成某种固定格式的配置文件,并具有增删改查操作。

import configparserconfig = configparser.ConfigParser()    # 相当于一个空字典 {}
config['DEFAULT'] = {'ServerAliveInterval': '45','Compression': 'yes','CompressionLevel': '9'}config['bitbucket.org'] = {}config['bitbucket.org']['User'] = 'hg'config['topsecret.server.com'] = {}topsecret = config['topsecret.server.com']topsecret['Host Port'] = '50022'topsecret['ForwardX11'] = 'no'config['DEFAULT']['ForwardX11'] = 'yes'with open('config.ini', 'w') as f:config.write(f)
# config.ini
[DEFAULT]
serveraliveinterval = 45
compression = yes
compressionlevel = 9
forwardx11 = yes[bitbucket.org]
user = hg[topsecret.server.com]
host port = 50022
forwardx11 = no

增删改查操作

import configparser
config = configparser.ConfigParser()#-------------------------查---------------------------config.read('config.ini')   # 读取文件# 打印所有块名,除默认 DEFAULT 以外
print(config.sections())     #['bitbucket.org', 'topsecret.server.com']# 判断某行是否在里面
print('bytebong.com' in config)     # False# 查询某个块下某个值
print(config['bitbucket.org']['user'])      # hg# 查询默认块下某个值
print(config['DEFAULT']['compression'])     # yes# 遍历某个块的所有键信息		遍历时会打印 default 的信息
for key in config['bitbucket.org']:print(key)
# user
# serveraliveinterval
# compression
# compressionlevel
# forwardx11# 查询某个块的所有键信息,以列表形式显示
print(config.options('bitbucket.org'))      # ['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11']# 查询某个块的所有键信息,以列表二元组形式显示
print(config.items('bitbucket.org'))# [('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')]#---------------增-----------------------
# 增加块
config.add_section('yuan')# 增加块下键值信息
config.set('yuan', 'k1', '1111')#-----------删-----------------
# 删除块
config.remove_section('topsecret.server.com')# 删除块下键值
config.remove_option('bitbucket.org', 'user')config.write(open('new_config.ini', 'w'))

**Tips:**DEFAULT 用来存储必要的信息,以便每次遍历时能打印。增删改操作必须重新写入文件,可以是同文件名

2.11 hashlib 模块

在加密操作中,Python 3.x 用 hashlib 模块替代了 md5 和 sha 模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法。

MD5 算法

import hashlibm = hashlib.md5()		# 创建一个对象m.update('hello'.encode('utf8'))		# 对 hello 进行加密
print(m.hexdigest())      # 5d41402abc4b2a76b9719d911017c592m.update('admin'.encode('utf8'))		# 对 admin 进行加密
print(m.hexdigest())        # dbba06b11d94596b7169d83fed72e61bm2 = hashlib.md5()				
m2.update('helloadmin'.encode('utf8'))
print(m2.hexdigest())       # dbba06b11d94596b7169d83fed72e61b

m 对象加密字符串 hello,再加密 admin 得到的结果和 m2 对象之间加密 helloadmin 的结果一样。

以上加密算法虽然比较厉害,但还是可以通过撞库反解,所有可以在加密算法中添加自定义 key 再加密。

import hashlib
m = hashlib.md5('dfkey'.encode('utf8'))		# 添加自定义 key,(随意)
m.update('hello'.encode('utf8'))
print(m.hexdigest())		# a674e0a8aa1a489ce67538a28c60abbf

sha256 算法

与 md5 算法用法一致:

m = hashlib.sha256()
m.update('hello'.encode('utf8'))
print(m.hexdigest())2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

还有一个 hmac 模块,它内部对我们创建 key 和内容再处理然后加密:

import hmach = hmac.new('rose'.encode('utf8'))
h.update('hello'.encode('utf8'))
print(h.hexdigest())		# a3b661e7d63a4eb65acb8223f96e2241

2.12 hamc 模块

实现标准的 Hmac 算法

方法:

# 产生一个新的哈希对象,并返回
# 随机 key,msg,哈希算法(默认 md5)
h = hmac.new(key, msg=None, digestmod=None)# 获取哈希对象的散列值
h.digest()# 和 digest() 一样,但返回的是一串十六进制数字
h.hexdigest()# 用新的字符串 msg2 去更新哈希对象
h.update(msg2)

示例:

import hmackey = b'I love python'
msg = b'python'h = hmac.new(msg, key, digestmod='md5')
digest = h.digest()
hexdigest = h.hexdigest()
print(digest)
print(hexdigest)msg2 = b'pycharm'
h.update(msg2)
print(h.hexdigest())
b'\xda\xf3\x0c\xa5\x175Cka\x9e\xa9\r\x1d\x0c{<'
daf30ca51735436b619ea90d1d0c7b3c
c976aa6fb6689c16a804eac9bf18d311

Tips: msg 和 key 必须是 bytes 类型

2.13 struct 模块

在网络通信中,大多数数据以二进制形式(binary data)传输。当传递的是字符串时,没有必要担心太多问题。但是若传递的数 int、float 等类型时,就需要将它们打包成二进制形成,再进行网络传输。而 struct 模块就提供了这样的机制。

2.13.1 pack 和 unpack

struct 提供用 format specifier 方式对数据进行打包和解包(packing and unpacking):

>>> import struct
>>> pack_data = struct.pack('hhl', 1, 2, 3)		# h 两个 2 进制位,l 4个,总共 8个
>>> pack_data
b'\x01\x00\x02\x00\x03\x00\x00\x00'>>> unpack_data = struct.unpack('hhl', pack_data)
>>> unpack_data
(1, 2, 3)>>> struct.pack('i', 1234134)	# 表示 1234134 安装 i 格式化,i 为 int,长度为 4,因此这里是将数字转换为 4 个二进制数
b'\xd6\xd4\x12\x00'

字符串:

import structmsg = b'python'		# 必须是字节型
s = struct.pack('5s', msg)
print(s)
print(struct.unpack('5s', s))
print(s.size)
b'pytho'
(b'pytho',)
16
format specifier 对照表

需要注意的是解包浮点数,精度会有所变化,这是由一些比如操作系统等客观因素所决定:

>>> import struct
>>> data_pack = struct.pack('f', 12.2)
>>> struct.unpack('f', data_pack)
(12.199999809265137,)

2.13.2 字节顺序

打包后的字节顺序默认由操作系统决定,struct 模块也提供了可以自定义顺序的功能。对于一些底层通讯字节顺序很重要,不同的字节顺序会导致字节大小的不同。

我们只需要在 format 字符串前面加上特定的符号即可表示不同的字节顺序存储方式,如:采用小端存储:

data_pack = struct.pack('<hhl', 1,2,3)

2.13.3 利用 buffer,使用 pack_into 和 unpack_from 方法

使用二进制打包数据大部分场景都是对性能要求比较高的使用环境,pack 方法每次都需要重新创建一个内存空间用于返回,也就是每次都要分配相应的内存,这是一种很大的浪费。

struct 模块的 pack_into()、unpack_from() 方法,正好可以用来解决这种问题。它会对一个提取分配好的 buffer 进行字节填充,而不是每次都产生一个新对象进行存储。

pack_into(format, buffer, offerset, v1, v2...)	# 格式, buffer, 偏移量(必须), 值

示例:

import struct
import ctypesvalues = (1, b'python', 2.7)
s = struct.Struct('I6sf')prebuffer = ctypes.create_string_buffer(s.size)  # 创建一个 buffer 对象data_pack = s.pack_into(prebuffer, 0, *values)
data_unpack = s.unpack_from(prebuffer, 0)print(data_pack)
print(data_unpack)
None
(1, b'python', 2.700000047683716)

pack_into() 和 unpack_from() 都是对 buffer 对象进行操作,没有产生多余的内存浪费。而且可以将多个 struct 对象 pack 到一个 buffer 对象里,然后指定不同的 offset 进行 unpack:

import struct
import ctypes
import binasciivalue1 = (1, b'python', 2.7)
value2 = 9999
s1 = struct.Struct('I6sf')
s2 = struct.Struct('I')prebuffer = ctypes.create_string_buffer(s1.size + s2.size)  # 创建一个 buffer 对象
print('pack之前', binascii.hexlify(prebuffer))data_pack_s1 = s1.pack_into(prebuffer, 0, *value1)
data_pack_s2 = s2.pack_into(prebuffer, s1.size, value2)data_unpack_s1 = s1.unpack_from(prebuffer, 0)
data_unpack_s2 = s2.unpack_from(prebuffer, s1.size)print(data_unpack_s1)
print(data_unpack_s2)
print('pack之后', binascii.hexlify(prebuffer))
pack之前 b'0000000000000000000000000000000000000000'
(1, b'python', 2.700000047683716)
(9999,)
pack之后 b'01000000707974686f6e0000cdcc2c400f270000'

参考:http://www.cnblogs.com/yuanchenqi/articles/5732581.html

相关文章:

Python 模块和包

1. 模块和包 **容器&#xff1a;**列表、元组、字符串、字典等&#xff0c;对数据的封装**函数&#xff1a;**对语句的封装**类&#xff1a;**对方法和属性的封装&#xff0c;即对函数和数据的封装 而模块&#xff08;module&#xff09;就是个程序&#xff0c;一个.py 文件&…...

Java零基础专栏——面向对象

1 面向对象思想1.1 什么是面向对象&#xff1f;2 类和对象2.1 类和对象的理解2.2 类的定义2.3定义类的补充注意事项2.4 对象的使用2.5 练习3 封装3.1 封装思想3.1.1 封装概述3.1.2 封装的步骤3.1.3 封装代码实现3.2 private关键字3.3 练习—private的使用4 构造方法4.1 构造方法…...

离散无记忆与有记忆信源的序列熵

本专栏包含信息论与编码的核心知识&#xff0c;按知识点组织&#xff0c;可作为教学或学习的参考。markdown版本已归档至【Github仓库&#xff1a;information-theory】&#xff0c;需要的朋友们自取。或者公众号【AIShareLab】回复 信息论 也可获取。 文章目录离散无记忆信源的…...

算法该不该刷?如何高效刷算法?

一、算法该不该刷&#xff1f;最近有小伙伴向我咨询一个问题&#xff0c;就是算法该不该刷&#xff0c;该如何刷算法呢&#xff1f;这个问题可谓太大众化了&#xff0c;只要你去某乎、某度搜索一下相关的解答&#xff0c;会有无数种回答&#xff0c;可见这个问题困扰了多少学习…...

Allegro如何在关闭飞线模式下查看网络连接位置操作指导

Allegro如何在关闭飞线模式下查看网络连接位置操作指导 在用Allegro做PCB设计的时候,有时会因为设计需要,关闭飞线显示。 如何在关闭飞线显示模式下查看网络连接的位置,如下图 除了能看到网络连接的点位以外,还能看到器件的pin Number 如何显示出这种效果,具体操作如下 …...

啊哈 算法读书笔记 第 1 章 一大波数正在靠近——排序

目录 排序算法&#xff1a; 时间复杂度&#xff1a; 排序算法和冒泡排序之间的过渡&#xff1a; 冒泡排序 冒泡排序和快速排序之间的过渡&#xff1a; 快速排序 排序算法&#xff1a; 首先出场的是我们的主人公小哼&#xff0c;上面这个可爱的娃就是啦。期末考试完了老…...

Servlet笔记(5):HTTP请求与响应

1、HTTP请求 当浏览器请求网页时&#xff0c;它会向Web服务器发送特定信息&#xff0c;这些信息不能被直接读取&#xff0c;而是通过传输HTTP请求时&#xff0c;封装进请求头中。 有哪些头信息&#xff1f; 头信息描述Accept这个头信息指定浏览器或其他客户端可以处理的 MIME…...

信号的运算与变换

目录 前言 本章内容介绍 信号的运算与变换 相加 相乘 时移 反折 尺度变换 微分&#xff08;差分&#xff09; 积分&#xff08;累加&#xff09; 信号的奇偶求解 信号的实虚分解 合适的例题 1、时移反折 2、时移尺度 3、时移反折尺度 4、反求x(t) 前言 《信号…...

【GO】K8s 管理系统项目9[API部分--Secret]

K8s 管理系统项目[API部分–Secret] 1. 接口实现 service/dataselector.go // secret type secretCell corev1.Secretfunc (s secretCell) GetCreation() time.Time {return s.CreationTimestamp.Time }func (s secretCell) GetName() string {return s.Name }2. Secret功能…...

ESP32 Arduino EspNow点对点双向通讯

ESP32 Arduino EspNow点对点双向通讯✨本案例分别采用esp32和esp32C3之间点对点单播无线通讯方式。 &#x1f33f;esp32开发板 &#x1f33e;esp32c3开发板 &#x1f527;所需库(需要自行导入到Arduino IDE library文件夹中&#xff0c;无法在IDE 管理库界面搜索下载到该库)&am…...

Linux SID 开发指南

Linux SID 开发指南 1 前言 1.1 编写目的 介绍Linux 内核中基于Sunxi 硬件平台的SID 模块驱动的详细设计&#xff0c;为软件编码和维护提供基 础。 1.2 适用范围 内核版本Linux-5.4, Linux-4.9 的平台。 1.3 相关人员 SID 驱动、Efuse 驱动、Sysinfo 驱动的维护、应用开…...

Matlab进阶绘图第2期—线型热图

线型热图由共享X轴的多条渐变直线组成&#xff0c;其颜色表示某一特征值。 与传统热图相比&#xff0c;线型热图适应于X轴数据远多于Y轴&#xff08;条数&#xff09;的情况&#xff0c;可以很好地对不同组数据间的分布情况进行比较&#xff0c;也因此可以在一些期刊中看到它的…...

【Redis中bigkey你了解吗?bigkey的危害?】

一.Redis中bigkey你了解吗&#xff1f;bigkey的危害&#xff1f; 如果面试官问到了这个问题&#xff0c;不必惊慌&#xff0c;接下来我们从什么是bigkey&#xff1f;bigkey划分的类型&#xff1f;bigkey危害之处&#xff1f; 二.什么是bigkey&#xff1f;会有什么影响&#xff…...

C++回顾(一)——从C到C++

前言 在学习了C语言的基础上&#xff0c;C到底和C有什么区别呢&#xff1f; 1.1 第一个C程序 #include <iostream>// 使用名为std的命名空间 using namespace std;int main() {// printf ("hello world\n");// cout 标准输出 往屏幕打印内容 相当于C语言的…...

CRF条件随机场 | 关键原理+面试知识点

😄 CRF之前跟人生导师:李航学习过,这里结合自己的理解,精简一波CRF,总结一下面试中高频出现的要点。个人觉得没网上说的那么复杂,我看网上很大部分都是一长篇先举个例子,然后再说原理。没必要原理其实不难,直接从原理下手更好理解。 文章目录 1、概率无向图(马尔可夫…...

秒懂算法 | 回归算法中的贝叶斯

在本文中,我们会用概率的观点来看待机器学习模型,用简单的例子帮助大家理解判别式模型和生成式模型的区别。通过思考曲线拟合的问题,发现习以为常的损失函数和正则化项背后有着深刻的意义 01、快速理解判别式模型和生成式模型 从概率的角度来理解数据有着两个不同的角度,假…...

用Netty实现物联网01:XML-RPC和JSON-RPC

最近十年,物联网和云计算、人工智能等技术一道,受到业内各方追捧,被炒得火热,甚至还诞生了AIoT这样的技术概念。和(移动)互联网不同,物联网针对的主要是一些资源有限的硬件设备,比如监控探头、烟雾感应器、温湿度感应器、车载OBD诊断器、智能电表、智能血压计等。这些硬…...

腾讯云服务器centos7安装python3.7+,解决ssl问题

使用requests模块访问百度&#xff0c;报错如下&#xff1a; requests.exceptions.SSLError: HTTPSConnectionPool(hostwww.baidu.com, port443): Max retries exceeded with url: / (Caused by SSLError("Cant connect to HTTPS URL because the SSL module is not avail…...

C++【模板STL简介】

文章目录C模板&&STL初阶一、泛型编程二、函数模板2.1.函数模板概念2.2.函数模板格式2.3.函数模板的实例化2.4.模板参数的匹配原则三、 类模板3.1.模板的定义格式3.2.类模板的实例化STL简介一、STL的概念、组成及缺陷二、STL的版本C模板&&STL初阶 一、泛型编程…...

该学会是自己找bug了(vs调试技巧)

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; c语言初阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:介绍c语言初阶的最后一篇.有关调试的重要性. 金句分享…...

Redis大全(概念与下载安装)

目录 一、概念 1.非关系型数据库&#xff08;NoSQL&#xff09;的介绍 2.什么是redis 3.redis的作者 4.Redis的特点 5.redis的应用场景 6.高度概括知识 一、二 缓存穿透、缓存击穿、缓存雪崩的概念 &#xff08;一&#xff09;缓存穿透 &#xff08;二&#xff09;缓…...

指针的进阶【上篇】

文章目录&#x1f4c0;1.字符指针&#x1f4c0;2.指针数组&#x1f4c0;3.数组指针&#x1f4bf;3.1.数组指针的定义&#x1f4bf;3.2. &数组名VS数组名&#x1f4bf;3.3.数组指针的使用&#x1f4c0;1.字符指针 int main() {char ch w;char* pc &ch;// pc就是字符指…...

MATLAB | 如何用MATLAB绘制花里胡哨的山脊图

本期推送教大家如何绘制各种样式的山脊图&#xff0c;这里做了一个工具函数用来实现好看的山脊图的绘制&#xff0c;编写不易请多多点赞&#xff0c;大体绘制效果如下&#xff1a; 依旧工具函数放在文末。 教程部分 0 数据准备 数据为多个一维向量放在元胞数组中&#xff0c;…...

.Net与程序集

一个简单的C#程序回想一下我们第一个.net 程序 hello world&#xff0c;它具有那些步骤呢&#xff1f;打开visual studio创建一个C# console的项目build运行程序这时候就有一个命令行窗口弹出来&#xff0c;上面打印着hello world。我们打开文件夹的bin目录&#xff0c;会发现里…...

软考中级之数据库系统(重点)

涉及考点:数据库模式,ER模型,关系代数与元祖演算,规范化理论,并发控制,分布式数据库系统,数据仓库和数据挖掘 数据库模式 三级模式-二级映射 常考选择题 三级模式,两种映射的这种涉及属于层次架构体的设计,这种设计为我们在应用数据库的时候提供了很多便利,同时提高了整个体…...

界面控件DevExtreme的Data Grid组件——让业务信息管理更轻松!

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#xff0c;使您可以利用现代Web开发堆栈&#xff08;包括React&#xff0c;Angular&#xff0c;ASP.NET Core&#xff0c;jQuery&#xff0c;Knockout等&#xff09;构建交互式的Web应用程序&#xff0c;该套件附带功能齐…...

【架构师】零基础到精通——网关策略

博客昵称&#xff1a;架构师Cool 最喜欢的座右铭&#xff1a;一以贯之的努力&#xff0c;不得懈怠的人生。 作者简介&#xff1a;一名退役Coder&#xff0c;软件设计师/鸿蒙高级工程师认证&#xff0c;在备战高级架构师/系统分析师&#xff0c;欢迎关注小弟&#xff01; 博主小…...

【java 8】方法引用与构造器引用

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…...

SGI 空间配置器

前言 空间配置器是 STL 六大组件之一&#xff0c;它总是隐藏在容器的背后&#xff0c;默默工作&#xff0c;默默付出。本文为《STL 源码剖析》读书笔记&#xff0c;主要讨论 SGI 版本空间的配置和释放&#xff0c;对代码进行解读时会改变一些写法&#xff0c;使其更易于阅读。…...

2023年白酒行业研究报告

第一章 行业概况 白酒是中国传统的酿酒业之一&#xff0c;历史悠久&#xff0c;源远流长。白酒指以高粱等粮谷为主要原料&#xff0c;以大曲、小曲或麸曲及酒母等为糖化发酵剂&#xff0c;经蒸煮、糖化、发酵、蒸馏、陈酿、勾兑而制成的&#xff0c;酒精度(体积分数)在18%-68%…...