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

Python语法学习篇(七)【py3】

内建模块

除去前文提到过的模块,Py内置了许多有用的模块。本文详细附上一些示例代码来了解一些模块。

collections

Python 内建的一个集合模块,提供了许多有用的集合类,我们将其展开来讲

nametuple

普通的 tuple 只能通过下标取值,不够直观。p=(1,2),直观来看很难看懂这个是坐标还是别的。
namedtuple 可以让元素带名字,用属性访问,更易读

from collections import namedtuple# 定义一个 Point 类型,包含 x 和 y
Point = namedtuple('Point', ['x', 'y'])p = Point(1, 2)print(p.x, p.y)   # 1 2
print(isinstance(p, tuple))  # True

再比如表示圆:

Circle = namedtuple('Circle', ['x', 'y', 'r'])
c = Circle(0, 0, 5)
print(c)   # Circle(x=0, y=0, r=5)

其式子如下:

# namedtuple('名称', [属性 list])

deque

普通的 list 在头部插入/删除效率低,deque(双端队列)在两端操作都很快,适合用于队列和栈

from collections import dequeq = deque(['a', 'b', 'c'])
q.append('x')      # 右侧添加
q.appendleft('y')  # 左侧添加print(q)  # deque(['y', 'a', 'b', 'c', 'x'])print(q.pop())      # 从右取出 → 'x'
print(q.popleft())  # 从左取出 → 'y'

defaultdict

普通 dict 访问不存在的 key 会报错,抛出KeyError,defaultdict 可以给个默认值

from collections import defaultdictdd = defaultdict(lambda: "N/A")dd["name"] = "Tom"
print(dd["name"])  # Tom
print(dd["age"])   # N/A (不存在的 key 返回默认值)
除了在 Key 不存在时返回默认值,defaultdict 的其他行为跟 dict 是完全一样的

OrderedDict

不同于py2的无序key的dict,py3.7+的dict默认就是有序的。但OrderedDict在py3仍有特殊的作用
from collections import OrderedDict
d = dict([('a', 1), ('b', 2), ('c', 3)])
print(d)od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
print(od)

d1=dict()
d1['a']=1
d1['b']=2
d1['c']=3
print(d1.keys())od1=OrderedDict()
od1['a']=1
od1['c']=3
od1['b']=2
print(od1.keys())

可以看到,现在dict已经默认带有了order属性

📌 特殊用法:实现一个 固定大小的 FIFO 缓存

from collections import OrderedDictclass LastUpdatedOrderedDict(OrderedDict):def __init__(self, capacity):super().__init__()self._capacity = capacitydef __setitem__(self, key, value):if key in self:del self[key]   # 先删除旧的elif len(self) >= self._capacity:self.popitem(last=False)  # 删除最早的super().__setitem__(key, value)# 使用
cache = LastUpdatedOrderedDict(2)
cache["a"] = 1
cache["b"] = 2
cache["c"] = 3
print(cache)  # OrderedDict([('b', 2), ('c', 3)])

Counter

最常见的计数器,本质也是dict的子类

from collections import Counterc = Counter("programming")
print(c)
# Counter({'r': 2, 'g': 2, 'm': 2, 'p': 1, 'o': 1, 'a': 1, 'i': 1, 'n': 1})
print(isinstance(c, dict))
print(c.most_common(2))#前两个高频元素
words = ["apple", "banana", "apple", "orange", "banana", "apple"]
c = Counter(words)
print(c)  # Counter({'apple': 3, 'banana': 2, 'orange': 1})

小结

工具功能常见场景示例代码(简化版)
namedtupletuple 元素起名字,支持属性访问坐标、圆形、学生成绩等固定数据结构python\nfrom collections import namedtuple\nPoint = namedtuple('Point', ['x', 'y'])\np = Point(1, 2)\nprint(p.x, p.y) # 1 2
deque双端队列,两端插入/删除效率高队列(FIFO)、栈(LIFO)、BFS 算法python\nfrom collections import deque\nq = deque(['a','b'])\nq.append('x'); q.appendleft('y')\nprint(q) # deque(['y','a','b','x'])
defaultdictdict 的扩展,不存在的 key 返回默认值统计、分组,避免 KeyErrorpython\nfrom collections import defaultdict\ndd = defaultdict(list)\ndd['fruits'].append('apple')\nprint(dd) # {'fruits': ['apple']}
OrderedDict保持插入顺序的 dictFIFO 缓存、顺序敏感的字典操作python\nfrom collections import OrderedDict\nod = OrderedDict()\nod['a']=1; od['b']=2\nprint(od) # OrderedDict([('a',1),('b',2)])
Counter计数器,统计元素出现次数统计字符/单词频率,高频分析python\nfrom collections import Counter\nc = Counter('banana')\nprint(c) # Counter({'a':3,'n':2,'b':1})

Base64

Base64是一种用64字符来表示任意二进制数据的方法。我们常常遇到用记事本打开某些文件时能看见一堆乱码。记事本这种文本处理软件没法处理一些二进制文件里的字符。所以需要一个二进制到字符串的转换方法。Base64就是其中一种。

其原理涉及计算机组成知识,本质是对二进制文件处理时每3个字节一组,也就是24bit。而后划分为4组,也就是6bit一组。这4个数字作为索引去查表,获得对应的4个字符,也就是编译后的字符串。因此整个流程下来会把3字节的二进制数据编码为4字节的文本。长度增加了1/3。

那如果出现二进制数据不是3的倍数怎么办?Base64会用\x00字节在末尾补足,同时加上1个或2个=号,用以表示补充了多少字节。在解码时就自动去掉了。

import base64
print(base64.b64encode(b'hello,World'))

,b表示Buffer类型

print(base64.b64decode(b'aGVsbG8sV29ybGQ='))

由于标准的 Base64 编码后可能出现字符+/,在 URL 中就不能直接作为参数,所以又有
一种"url safe"base64 编码,其实就是把字符+/分别变成-_
Base64 是一种通过查表的编码方法,不能用于加密,即使使用自定义的编码表也不行。
Base64 适用于小段内容的编码,比如数字证书签名、Cookie 的内容等。
由于=字符也可能出现在 Base64 编码中,但=用在 URLCookie 里面会造成歧义,所以,
很多 Base64 编码后会把=去掉
print(base64.b64encode(b'abcd'))
print(base64.b64decode(b'YWJjZA=='))
print(safe_b64decode('YWJjZA'))

print(base64.b64decode('YWJjZA'))

故而为了去掉=号也能正常解码,就采用safe_b64decode,其函数逻辑可以为下:

import base64def safe_b64decode(s: str) -> bytes:padding = 4 - len(s) % 4 if len(s) % 4 else 0s += "=" * paddingreturn base64.b64decode(s)print(safe_b64decode("YWJjZA"))  # b'abcd'

struct

准确地讲,Python 没有专门处理字节的数据类型。但由于 str 既是字符串,又可以表示字
节,所以,字节数组=str。而在 C 语言中,我们可以很方便地用 structunion 来处理字节,
以及字节和 intfloat 的转换。
  • 作用:二进制数据 ↔ Python 基本类型。

  • 用法:

    • pack(fmt, data...) → bytes

    • unpack(fmt, bytes) → tuple

  • 常见格式符:

    • I 4字节无符号整数

    • H 2字节无符号整数

    • > 大端序,< 小端序

import struct# 解析 BMP 文件头信息
def bmp_info(path: str):with open(path, "rb") as f:header = f.read(30)sig, _, size, _, offset, hdr_size, width, height, _, colors = \struct.unpack("<ccIIIIIIHH", header)if sig == b'B' and hdr_size == 40:print(f"Size: {width}x{height}, Colors: {colors}")else:print("Not a valid BMP")bmp_info("./test.bmp")

test.bmp请打开画图软件自行绘画,这里可以参考我的,在该文章绑定资源里寻找bmp文件。或是根据描述自行绘制。其程序结果大致如下:

关键点解析

  1. struct.unpack("<ccIIIIIIHH", header)

    • <小端序(BMP 文件使用小端格式)

    • cc → 2 个 char(对应文件标识,通常是 "BM"

    • I → 4 字节无符号整数 (unsigned int)

    • H → 2 字节无符号整数 (unsigned short)

    所以这个格式一共解析:

     

    cc   I I I I I I      H  H

  2. 2 + 4 + 4 + 4 + 4 + 4 + 4 + 2 + 2 = 32 字节

    注意:代码里只读了 30 字节,其实严格来说应该读 32 字节才完整。

  3. 变量含义

    • sig → 文件标识(通常 b'B'b'M',就是 "BM"

    • _ → 占位,不关心的字段(比如保留字段)

    • size → 整个 BMP 文件的大小(字节)

    • offset → 像素数据的起始偏移量

    • hdr_size → 信息头大小,标准 BMP 为 40

    • width → 图片宽度

    • height → 图片高度

    • colors → 调色板中的颜色数(如果为 0,则表示使用默认 2^n)

  4. 验证是否为标准 BMP

    • 文件开头必须是 "BM"

    • 信息头大小必须是 40(Windows 常见的 BITMAPINFOHEADER 结构)

struct请参考官方文档:struct — Interpret bytes as packed binary data — Python 3.13.7 documentation

hashlib

就是常见的哈希算法,散列算法。这种又称摘要算法。通过一个函数把任意长度的data转换成长度固定的数据串(一般是十六进制),也就是映射成类似于密钥的串来防止原文被篡改。

摘要算法是单向函数,计算f(data)得到结果很容易,但拿着结果反推data很困难。因此在网络安全领域有着广泛应用。

其代表有MD5、SHA1、SHA256…,感兴趣读者自行搜索

import hashlibdef get_md5(s: str) -> str:return hashlib.md5(s.encode("utf-8")).hexdigest()# 简单存储(不安全)
db = {"michael": get_md5("123456")}def login(user, pwd):return db.get(user) == get_md5(pwd)print(login("michael", "123456"))  # True

常用口令的MD5很容易就计算出来,我们可以通过对原始口令加一个复杂字符串来实现,也就是加盐防御:

db = {}
def register(username, password):db[username] = get_md5(password + username + "the-Salt")def login(username, password):return db.get(username) == get_md5(password + username + "the-Salt")
经过 Salt 处理的 MD5 口令,只要 Salt 不被黑客知道,即使用户输入简单口令,也很难通
MD5 反推明文口令。
但是如果有两个用户都使用了相同的简单口令比如 123456,在数据库中,将存储两条相同
MD5 值,这说明这两个用户的口令是一样的。有没有办法让使用相同口令的用户存储不
同的 MD5 呢?
如果假定用户无法修改登录名,就可以通过把登录名作为 Salt 的一部分来计算 MD5,从而
实现相同口令的用户也存储不同的 MD5

总之,摘要算法也不是加密算法,因为没法通过摘要反推明文,但可以防篡改,只需做验证就能确定用户身份。

itertools

  • 特点:生成迭代器,惰性计算,适合无限序列。

  • 常用函数:

    • count(start) → 无限自然数

    • cycle(seq) → 无限循环序列

    • repeat(obj, n) → 重复 n 次

    • takewhile(func, iter) → 条件截取

    • chain(iter1, iter2) → 串联

for c in chain('ABC', 'XYZ'):
print c
# 迭代效果:'A' 'B' 'C' 'X' 'Y' 'Z
  •  groupby(iter, keyfunc) → 相邻分组,迭代器中相邻的重复元素挑出来放在一起
import itertools# 取前10个自然数
nums = itertools.takewhile(lambda x: x <= 10, itertools.count(1))
print(list(nums))  # [1..10]# 分组
for k, g in itertools.groupby("AaaBBbcCAAa", key=lambda c: c.upper()):print(k, list(g))

http://www.dtcms.com/a/389875.html

相关文章:

  • 网页控制鼠标 查看鼠标位置
  • PIT 定时器
  • 【题解】 [蓝桥杯 2019 省 B] 特别数的和
  • 数字隔离器,串口通信的安全之“芯”
  • 山脊图 (Ridgeline Plot):使用 joypy 库,优雅地比较多组数据的分布情况
  • Linux 进程同步以及僵尸进程等知识介绍
  • Python进程和线程
  • 斐波那契数列的递归和迭代实现
  • 时空预测论文分享:规则知识 因果预测框架 面向研究的评估体系 主动适应漂移
  • 《WINDOWS 环境下32位汇编语言程序设计》第18章 ODBC数据库编程
  • linux入门(3)
  • 任意版本GitLens vscode插件破解邪修秘法
  • Redis最佳实践——热点数据缓存详解
  • font简写和CSS的继承性
  • 高性能服务器配置经验指南6——BIT校园网在ubuntu中的自动检查连接状况脚本使用
  • SQL 连接详解:内连接、左连接与右连接
  • C2000基础-TIM介绍及使用
  • Day 06 动作类的初始化类------以B1为例
  • 面试题:对数据库如何进行优化?
  • samurai 点选分割 box分割
  • 计算机架构的总线协议中的等待状态是什么?
  • C++:入门基础(1)
  • ACD智能分配:服务延续和专属客服设置
  • 自监督学习分割
  • 抛弃自定义模态框:原生Dialog的实力
  • LangGraph 简单入门介绍
  • Docker 部署 DzzOffice:服务器 IP 转发功能是否需要开启
  • 无人机避障——卡内基梅隆大学(CMU)CERLAB 无人机自主框架复现
  • 正点原子zynq_FPGA-初识ZYNQ
  • Vue3中对比ref,reactive,shallowRef,shallowReactive