【Python知识】 可哈希和不可哈希对象

2023-05-16

目录

一、说明

二、“可哈希”在Python中是什么意思?

2.1 什么是哈希(hashable)?

2.2 python的可哈希对象

2.3 实验和说明

2.4 什么是不可哈希(unhashable)?

三、更深的可哈希对象与不可哈希对象的理解

3.1 __hash__魔方函数

3.2 有关操作函数

3.3  自定义类型的对象是否可哈希的呢?

四、为什么字典 key 必须是不可变的(可哈希hashable)?

4.1 字典如何在 CPython 中实现?

4.2 字典 key 必须是不可变的(可哈希hashable)

五、总结


一、说明

        在python中,每个数据都是对象的。可是对象与对象是不同的。可以分可哈希对象和不可哈希对象,其存储方式不同。本文针对这个话题展开。

二、“可哈希”在Python中是什么意思?

2.1 什么是哈希(hashable)?

        解释python中可哈希对象的工作原理,必须首先了解术语“哈希”。

        散列(哈希)是计算机科学中的一个概念,用于创建高性能的伪随机访问数据结构,在该结构中要快速存储和访问大量数据。

        例如,如果您有10,000个电话号码,并且想要将它们存储在一个数组中(这是一个顺序数据结构,可将数据存储在连续的内存位置中,并提供随机访问),但是您可能没有所需的连续数量内存位置。

        您可以改为使用大小为100的数组,并使用哈希函数将一组值映射到相同的索引,并且这些值可以存储在链接列表中。这提供了类似于阵列的性能。至于这个原理细节可以参照我的博客:

      【数据管理】谈谈哈希原理和散列表_无水先生的博客-CSDN博客

2.2 python的可哈希对象

          简要的说可哈希的数据类型,即不可变的数据结构(数字类型(int,float,bool)字符串str、元组tuple、自定义类的对象)。

       所有不可变类型列表:

int, float, decimal, complex, bool, string, tuple, range, frozenset, bytes

        所有可变类型列表:

list, dict, set, bytearray, user-defined classes

        为什么不可变数据类型是可哈希hashable的呢? 

        对于不可变类型而言,不同的值意味着不同的内存,相同的值存储在相同的内存,如果将我们的不可变对象理解成哈希表中的Key,将内存理解为经过哈希运算的哈希值Value,这不正好满足哈希表的性质嘛。

        如果对象的哈希值在其生命周期内始终不变(需要一个__hash__()方法),并且可以与其他对象进行比较(需要一个__eq__()or __cmp__()方法),则该对象是可哈希的。比较相等的可哈希对象必须具有相同的哈希值。

散列性使对象可用作字典键和set成员,因为这些数据结构在内部使用散列值。

Python的所有不可变内置对象都是可哈希的,而没有可变容器(例如列表或字典)是可哈希的。作为用户定义类实例的对象默认情况下可哈希化;它们都比较不相等,并且其哈希值是id()

2.3 实验和说明

        用若干实验直接说明问题:

        实验1:常规变量理解,在变量不可变的情况,相同的值具备相同地址:

         理解什么是可变对象mutable与不可变对象inmutable。以及明白哈希值value的唯一性。

import numpy as np

a1 = 100
a2 = 100
a3 = 100
a4 = 200
a5 = 200
print( id(a1),id(a2),id(a3),id(a4),id(a5))

b1 = [1,2,3,4]
b2 = [1,2,3,4]
print(id(b1),id(b2))

c1 = (1,2,3,4,5,6)
print(hash(a1),hash(a2))
print(hash("b1"))

C:\anaconda3\python.exe C:/Users/yan/PycharmProjects/speechDev/myroad/tan.py
140726921526112 140726921526112 140726921526112 140726921529312 140726921529312
2368347700936 2368347700744
100 100
-7628306277453902763

Process finished with exit code 0


        实验2:任何不可变的东西(定义以后不能修改、追加、删除,类似于C++的const关键词)都可以被散列。

        除了要查找的哈希函数(如果有类)之外,还可以通过例如。dir(tuple)寻找__hash__方法(该方法返回布尔值,是或否),这里有一些例子

#x = hash(set([1,2])) #set unhashable
x = hash(frozenset([1,2])) #hashable
#x = hash(([1,2], [2,3])) #tuple of mutable objects, unhashable
x = hash((1,2,3)) #tuple of immutable objects, hashable
#x = hash()
#x = hash({1,2}) #list of mutable objects, unhashable
#x = hash([1,2,3]) #list of immutable objects, unhashable

        实验3:根据Python词汇表的理解,当您创建可哈希对象的实例时,还会根据实例的成员或值来计算不可更改的值。

        例如,该值随后可以用作字典中的键,如下所示:

>>> tuple_a = (1,2,3)
>>> tuple_a.__hash__()
2528502973977326415
>>> tuple_b = (2,3,4)
>>> tuple_b.__hash__()
3789705017596477050
>>> tuple_c = (1,2,3)
>>> tuple_c.__hash__()
2528502973977326415
>>> id(a) == id(c)  # a and c same object?
False
>>> a.__hash__() == c.__hash__()  # a and c same value?
True
>>> dict_a = {}
>>> dict_a[tuple_a] = 'hiahia'
>>> dict_a[tuple_c]
'hiahia'

        我们可以发现tuple_a和tuple_c的哈希值相同,因为它们具有相同的成员。当我们将tuple_a用作dict_a中的键时,我们可以发现dict_a [tuple_c]的值相同,这意味着,当它们用作dict中的键时,它们将返回相同的值,因为哈希值是相同。对于那些不可哈希的对象,方法哈希定义为“无”:

>>> type(dict.__hash__) 
<class 'NoneType'>

        我猜这个哈希值是在实例初始化时计算出来的,而不是以动态方式计算的,这就是为什么只有不可变对象才可以哈希的原因。希望这可以帮助。

        实验4:当我在Python 3中运行hash('Python')时,结果为5952713340227947791。不同版本的Python可以自由更改基础哈希函数,因此您可能会获得不同的值。重要的是,无论我现在多次运行hash('Python'),还是始终使用相同版本的Python获得相同的结果。

        但是hash('Java')返回1753925553814008565。因此,如果要散列的对象发生了变化,结果也将发生变化。另一方面,如果我正在哈希的对象没有更改,则结果保持不变。

        为什么这么重要?

        例如,Python字典要求键是不可变的。即,键必须是不变的对象。字符串在Python中是不变的,其他基本类型(int,float,bool)也是如此。元组和冻结集也是不可变的。另一方面,列表不是不可变的(即,它们是可变的),因为您可以更改它们。同样,字典是易变的。

因此,当我们说某事是可哈希的时,我们表示它是不可变的。如果我尝试将可变类型传递给hash()函数,它将失败:

>>> hash('Python')
1687380313081734297
>>> hash('Java')
1753925553814008565
>>>
>>> hash([1, 2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash({1, 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> hash({1 : 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
>>> hash(frozenset({1, 2}))
-1834016341293975159
>>> hash((1, 2))
3713081631934410656

查看英文原文

2.4 什么是不可哈希(unhashable)?

        同理,不可哈希的数据类型,即可变的数据结构 (字典dict,列表list,集合set)

        对于可变对象而言,比如一个列表,更改列表的值,但是对象的地址本身是不变的,也就是说不同的Key,映射到了相同的Value,这显然是不符合哈希值的特性的,即出现了哈希运算里面的冲突。如下:

a=[1,2,3]
print(id(a))
def func(p):
    p.append(4)
    return p


b=func(a)
print(id(b))
'''

2399750863880 是一样的哦

2399750863880

'''

        这种不能叫可哈希: 如果此时对a和b使用hash函数,则会出错,如下:

        TypeError: unhashable type: 'list'

三、更深的可哈希对象与不可哈希对象的理解

3.1 __hash__魔方函数

并不是说哈希值就是它本身哈,一个对象的哈希值是什么取决于__hash__魔方函数

再看一个例子:

In [24]: x="ilove"
In [25]: y="i"+"love"
In [26]: z="iloveyou"

In [27]: id(x),id(y),id(z)
Out[27]: (3122841661600, 3122841661600, 3122841929584) # x,y的id是一样的
In [28]: hash(x),hash(y),hash(z)

Out[28]: (4255912298523051991, 4255912298523051991, -3820205610162521985) # x,y 的哈希值是一样的

3.2 有关操作函数

        如果一个对象是可哈希的,那么在它的生存期内必须不可变(而且该对象需要一个哈希函数),而且可以和其他对象比较(需要比较方法).比较值相同的对象一定有相同的哈希值,即一个对象必须要包含有以下几个魔术方法:

  • __eq__():用于比较两个对象是否相等
  • __cmp__():用于比较两个对象的大小关系,它与__eq__只要有一个就可以了
  • __hash__():实际上就是哈希函数(散列函数),返回经过运算得到的哈希值

前面既然说了整数int是可哈希对象,不放我们看一下它具不具备这几个魔术方法:

In [51]: a=100
In [52]: dir(a)
Out[52]:

[...

'__eq__',

...

'__hash__',

...

]
  1. 我们发现他的确具有上面说的这几个魔术方法。列表是不可哈希的,我们看一下列表的魔术方法有哪一些:

In [54]: a=[1,2,3]

In [55]: dir(a)

Out[55]:

[...

'__eq__',

...

'__hash__',

...

']

        我们发现一个问题,为什么可变对象list明明是不可哈希的,为什么也有着两个方法呢?

        因为所有类型的基类object中实现了这两个魔术方法,但是并不是说有这两个方法就一定是可哈希的,关键是要如何实现__eq__()方法和__hash__()方法,list并没有实现,只是有这几个魔术方法而已,在实现的里面出发了上面的异常。我们可以看一下基类object的魔术方法,如下:

In [56]: dir(object)

Out[56]:

[...

'__eq__',

...

'__hash__',

...

]

3.3  自定义类型的对象是否可哈希的呢?

看一下如下代码:

class Animal:

def __init__(self, name):

self.name=name

def eat(self):

print("i love eat !")


a=Animal("dog")

print(hash(a)) # 83529594295

        我们发现自定义的类的对象是可哈希的,虽然我们不知道这个哈希值是如何得到的,但是我们知道他的确是可哈希对象。

        上面说了哈希值的计算实际上是通过__hash__魔术方法来实现的,我们不妨自定义一下类的魔术方法,如下:

class Animal:
def __init__(self, name):
self.name=name
def __hash__(self): # 自定义哈希函数
return 1000 # 注意哈希函数的返回值要是integer哦!
def eat(self):
print("i love eat !")
a=Animal("dog")
print(hash(a)) # 返回 1000

        现在对于什么是python的可哈希对象和哈希函数如何实现应该有了比较清楚的了解了。

四、为什么字典 key 必须是不可变的(可哈希hashable)?

4.1 字典如何在 CPython 中实现?

        CPython 的字典实现为可调整大小的哈希表。与 B-树相比,这在大多数情况下为查找(目前最常见的操作)提供了更好的性能,并且实现更简单。

        字典的工作方式是使用 hash() 内置函数计算字典中存储的每个键的 hash 代码。hash 代码根据键和每个进程的种子而变化很大;例如,"Python" 的 hash 值为-539294296,而"python"(一个按位不同的字符串)的 hash 值为 1142331976。然后,hash 代码用于计算内部数组中将存储该值的位置。假设您存储的键都具有不同的 hash 值,这意味着字典需要恒定的时间 -- O(1),用 Big-O 表示法 -- 来检索一个键。

4.2 字典 key 必须是不可变的(可哈希hashable)

        字典的哈希表实现使用从键值计算的哈希值来查找键。

(1)为什么可变对象不能作为键Key?

        先来看一个简单的例子:

  1. d = {[1, 2]: '100'} # 构造一个字典,key是列表[1,2] ,是一个可变对象,是不可哈希的

  2. print(d[[1, 2]]) # 通过key去访问字典的值,触发keyerror异常

复制

为什么会触发异常呢?哈希按其地址(对象 id)列出的。在上面的两行代码中,第一行中的key是一个列表对象[1,2],第二行中要访问的的时候的那个key虽然也是[1,2],但是由于列表list是可变对象,虽然这两行的列表值一样,但是他们并不是同一个对象,它们的存储地址是不一样的,即id是不一样的,id不一样也导致了根据id计算得到的哈希值是不一样的,自然没有办法找到原来的那一个[1,2]的哈希值在哪里了。

注意:这需要能够很好的理解可变对象与不可变对象的内存分配才好哦!

(2)为什么不可变对象能作为键Key?

将上面例子中的列表[1,2]换成元组(1,2),先来看一个简单的例子:

  1. d = {(1, 2): '100'} # 构造一个字典,key是元组(1,2) ,是一个不可变对象,是可哈希的

  2. print(d[(1, 2)]) # 通过key去访问字典的值,打印 '100'

        为什么这里不会触发异常呢?哈希按其地址(对象 id)列出的。在上面的两行代码中,第一行中的key是一个元组对象(1,2),第二行中要访问的的时候的那个key也是(1,2),但是由于元组tuple是不可变对象,那么这两行的元组值一样,所以它们的存储地址是一样的,即id是一样的,id一样也导致了根据id计算得到的哈希值是一样的,哈希值一样我自然可以搜索得到那个100在哪个地方了。

五、总结

1)凡是有常量性质的对象可以哈希化。

2)正是常量这种不变性质,可以将它们的内容(或值)映射到具体地址上(想想,如果内容可变是不是地址映射不唯一?)

3)可哈希下有一堆魔方方法可以有意识地调用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Python知识】 可哈希和不可哈希对象 的相关文章

  • 如何在Windows的cmd下让程序在后台执行

    如何在Windows的cmd下让程序在后台执行 xff1f Hu Dennis 2008 12 24 在windows下启动JBoss服务器 xff0c 需要在命令行中输入run bat 但是运行后如果你想停止服务器 xff0c 可能的做法
  • 嵌入式LINUX识别U盘的问题

    我试过mount U盘 当开机后mount 第一个U盘时 xff0c 一般设备名为sda xff0c 然后umount xff0c 并重插另外一个U盘 xff0c 再mount xff0c 发现设备名变为sdb了 此试验进行了几次 xff0
  • yolov4+deepsort(yolo目标检测+自适应卡尔曼滤波追踪+毕业设计代码)

    项目介绍 该项目一个基于深度学习和目标跟踪算法的项目 xff0c 主要用于实现视频中的目标检测和跟踪 该项目使用了 YOLOv4 目标检测算法和 DeepSORT 目标跟踪算法 xff0c 以及一些辅助工具和库 xff0c 可以帮助用户快速
  • 集成学习(含常用案列)

    集成学习原理 xff1a 工作原理是生成多个分类器 模型 xff0c 各自独立地学习和作出预测 这些预测最后结合成组合预测 xff0c 因此优于任何一个单分类的做出预测 集成学习算法分类 xff1a 集成学习算法一般分为 xff1a bag
  • 字节序与比特序详解

    字节序的定义 几种类型的字节序 cpu字节序外部bus字节序设备字节序网络协议字节序 Ethernet协议字节序IP协议字节序 编译字节序 比特序的定义字节序与bit序的转换结构体的位域 字节序的定义 字节序就是说一个对象的多个字节在内存中
  • 【动态规划】01背包问题

    问题描述 有n个物品 xff0c 它们有各自的体积和价值 xff0c 现有给定容量的背包 xff0c 如何让背包里装入的物品具有最大的价值总和 xff1f 为方便讲解和理解 xff0c 下面讲述的例子均先用具体的数字代入 xff0c 即 x
  • 献给初学labview数据采集的初学者

    前言 xff1a 参考来源 xff1a http bbs elecfans com jishu 209658 1 5 html xff0c 感谢原作者 zhihuizhou 这里的内容只针对NI的数据采集卡 xff0c 不保证适用于其它公司
  • 如何从科学论文中实现一个算法

    原文 xff1a http codecapsule com 2012 01 18 how to implement a paper 作者 xff1a Emmanuel Goossaert 本文是从科学论文中实现算法的简短指南 我从书籍和科学
  • 国内C/C++刷题网站汇总

    作者 xff1a Luau Lawrence 链接 xff1a https www zhihu com question 25574458 answer 31175374 来源 xff1a 知乎 Welcome To PKU JudgeOn
  • 华为16道经典面试题

    面试过程中 xff0c 面试官会向应聘者发问 xff0c 而应聘者的 回答将成为面试官考虑是否接受他的重要依据 对应聘者而言 xff0c 了解这些问题背后的 猫腻 至关重要 本文对面试中经常出现的一些典型问题进行了整理 xff0c 并给出相
  • 语音信号的预加重和加窗处理

    原文转载于 xff1a http blog csdn net ziyuzhao123 article details 12004603 非常感谢 一 语音信号的预加重 语音信号的预加重 xff0c 目的是为了对语音的高频部分进行加重 xff
  • 单独编译和使用webrtc音频增益模块(AGC)

    原文转载于 xff1a http www cnblogs com mod109 p 5767867 html top 非常感谢 webrtc的音频处理模块分为降噪ns xff08 nsx xff09 xff0c 回音消除aec xff08
  • 功率谱和频谱的区别

    生活中很多东西之间都依靠信号的传播 xff0c 信号的传播都是看不见的 xff0c 但是它以波的形式存在着 xff0c 这类信号会产生功率 xff0c 单位频带的信号功率就被称之为功率谱 它可以显示在一定的区域中信号功率随着频率变化的分布情
  • 如何解决在rviz中,路径规划导航时,点击2D Pose estimate后机器人位置没有改变,终端也没有反应的问题

    在rviz中 xff0c 点击2D Pose estimate后机器人位置没有改变 xff0c 终端也没有反应 xff0c 通常这种情况就是由于客户端和服务端IP地址不一致导致的 xff0c IP地址有时候系统会自动变更 xff0c 这里我
  • 五款免费开源的语音识别工具

    按 xff1a 本文原作者 Cindi Thompson xff0c 美国德克萨斯大学奥斯汀分校 xff08 University of Texas at Austin xff09 计算机科学博士 xff0c 数据科学咨询公司硅谷数据科学
  • 动态内存分配

    动态内存分配 常见的内存分配的错误 先上一个内存分配的思维导图 便于联想想象 xff0c 理解 xff1a 首先我们介绍一下内存分配的方式 xff1a 1 在静态存储区域中进行分配 内存在程序编译的时候就已经分配好 xff0c 这块内存在程
  • UEFI架构

    UEFI架构 UEFI提供系统化的标准方法 xff0c 加载驱动并管理他们之间的交互 前言 xff1a 感谢uefi blog UEFI 提供了一个标准接口 xff0c 以便在硬件发生变更时固件能提供足够信息而保证操作系统不受影响 它包含有
  • C++调试工具(未完)

    C 43 43 调试相关命令 ld so conf https blog csdn net Bruce 0712 article details 78816790相关的命令 ar nm 目标格式文件分析 xff0c 所以也可以分析 a文件
  • 11_UART串口

    11 UART 文章目录 11 UART1 串口连接芯片图2 串口传输一个字节的过程3 发送接收过程4 编写UART函数4 1 初始化函数uart0 init 4 1 1 设置引脚用于串口4 1 2 使能上拉4 1 3 设置波特率4 1 4
  • 汇编指令:LDMIA、LDMIB、LDMDB、LDMDA、STMIA、LDMFD、LDMFA、LDMED、LDMEA

    ARM指令中多数据传输共有两种 xff1a LDM load much xff1a 多数据加载 将地址上的值加载到寄存器上 STM store much xff1a 多数据存储 将寄存器的值存到地址上 主要用途 xff1a 现场保护 数据复

随机推荐

  • C++ 实现 发送HTTP Get/Post请求

    1 简述 最近简单看了一下关于HTTP请求方面的知识 xff0c 之前一直用Qt来实现 xff0c 有专门HTTP请求的QNetworkAccessManager类来处理 xff0c 实现也比较简单 xff0c 这里主要讲解一下用C 43
  • [Simple] 洗牌算法

    题目要求 xff1a 平时洗牌是两打牌 xff0c 交叉洗在一起 也就是开始 1 2 3 4 5 6 7 8 第一次 1 5 2 6 3 7 4 8 第二次 1 3 5 7 2 4 6 8 第k次 给你一个数组a 2N xff0c 要求在O
  • 【PID控制原理及其算法】

    前言 本文以自己的学习过程总结而来 xff0c 将自己的经验写出来以供大家一起学习 xff0c 如有错误请多指教 一 PID是什么 xff1f PID就是比例 积分 微分 xff0c PID算法可以说是在自动控制原理中比较经典的一套算法 x
  • printf重定向的相关总结

    简介 实现printf重定向有多种方式 xff0c 下面一一介绍 linux环境下 虽然linux系统的默认标准输出设备是显示器 xff0c 但是我们可以把printf打印输出的内容重定向到其他设备或文件 方法如下 xff1a 方法1 xf
  • 开发者七问七答:什么是产品化?

    简介 xff1a 之前参加了企业智能部门如何做产品化的讨论 xff0c 大家对产品化的定义和过程都有各自不同的见解 我觉得这个话题其实可以扩展下 xff0c 想站在一个开发人员的视角尝试探讨一下产品化 下面以自问自答的方式来展开 1 当我们
  • 系统调用和库函数及API的区别

    在写程序的过程中 xff0c 像MFC xff0c VC 43 43 这些编程 xff0c 都会涉及到函数的调用 xff0c 有库函数也有系统函数 xff0c 下面看一看它们的区别 xff01 xff01 系统调用 xff08 system
  • 应用服务器与zk之间的连接超时

    关于connectString服务器地址配置 格式 192 168 1 1 2181 192 168 1 2 2181 192 168 1 3 2181 这个地址配置有多个ip port之间逗号分隔 底层操作 span class hljs
  • 日本小学生走向APP开发私塾 智能手机迫切改变IT教育——日本经济新闻报道

    如要在日本接受专门的信息技术教育 xff08 IT xff09 xff0c 只有结束义务教育课程才能接受 如今 xff0c 打破这些障碍的趋势逐渐浓厚 因为从小就接触到各种数字机器和互联网而长大的 数字土著 xff08 digital na
  • 步进电机和伺服电机的区别

    步进电机作为一种开环控制的系统 xff0c 和现代数字控制技术有着本质的联系 在目前国内的数字控制系统中 xff0c 步进电机的应用十分广泛 随着全数字式交流伺服系统的出现 xff0c 交流伺服电机也越来越多地应用于数字控制系统中 为了适应
  • 【图像处理】墨西哥小波和带通滤波

    一 说明 在连续小波的家族当中 xff0c 埃尔米特小波是个非常特别的存在 xff08 应用在连续小波转换称作埃尔米特转换 xff09 Ricker子波计算电动力学的广谱源项 它通常只在美国才会被称作墨西哥帽小波 xff0c 因为在作为核函
  • 【halcon知识】应用仿射变换

    一 说明 无论什么样的变换 xff0c 都离不开齐次变换矩阵 一般地 xff0c 先准备一个空的齐次变换矩阵 xff0c 这个矩阵随便填写 xff1a 1 xff09 填入旋转类参数就是旋转矩阵 xff0c 2 填入仿射参数就可进行仿射变换
  • 【ROS2知识】SQLite数据库

    目录 一 说明 二 介绍SQLite 三 安装 3 1 简单测试 生成一个表 3 2 sqlite 共五种数据类型
  • open3D

    目录 一 说明 二 如何安装open3d xff1f 三 显示点云数据 3 1 显示点云场景数据 3 2 体素下采样 3 3 顶点法线估计 一 说明 对于点云 处理 xff0c 这里介绍哦pen3d xff0c 该软件和opencv同样是i
  • 【计算几何7】帝国边界划分问题【Voronoi图的原理】

    目录 一 说明 二 帝国边界划分问题 三 voronoi的正规定义 3 1 最简单的voronoi情况 3 2 在距离空间的数学描述 3 3 不同距离空间所得 Voronoi 单元不同 四 代码和库 4 1 算法库 4 2 参数说明 4 3
  • 【python视图2】基于networkx的10个绘图技巧

    目录 一 说明 二 简单图操作种种 2 1 简单的无向图 2 2 简单的有向图 2 3 二维网格grid图 和边数据读写 2 4 环图 2 5 全连接神经网络 2 6 分布直方图 度秩图 连同子图 2 7 随机生成 2 8 渐变颜色化 2
  • ESP32控制TDC-GP22测量超声传播时间(超声流量计)

    TDC GP22控制的资料 xff0c 网上的资源都是基于STM32或者MSP430主控的 xff0c 但现在这两款芯片都太贵了 xff0c 因此就想用便宜点的ESP32 xff0c 折腾了快一周 xff0c 终于弄好了 工程源码和参考资料
  • 【python视图3】networkx图操作示例

    目录 一 说明 二 神奇制图 2 1 绘制彩虹图 2 2 随机地理图 2 3 旅行商问题 2 4 权重的灵活绘制 2 5 barabasi albert模型1 2 6 barabasi albert模型2 2 7 igraph操作 一 说明
  • 【python视图1】networkx操作Graph图

    目录 一 说明 二 生成图 xff08 Creating a graph xff09 2 1 创建一个没有节点和边的空图 2 2 在空图追加节点 2 3 追加边 xff08 Edges xff09 2 4 删除节点 2 5 查询 三 使用图
  • 【python】错误TypeError: ‘dict_values‘ object does not support indexing when的改出

    一 说明 在使用python的dict和索引时 xff0c 在早期的python可以 xff0c 但后来不可以了 因此 xff0c 在python执行语句 xff1a names i d values i for i in range le
  • 【Python知识】 可哈希和不可哈希对象

    目录 一 说明 二 可哈希 在Python中是什么意思 xff1f 2 1 什么是哈希 hashable xff1f 2 2 python的可哈希对象 2 3 实验和说明 2 4 什么是不可哈希 unhashable xff1f 三 更深的