本文基于pycharm编译器,也可以使用Anaconda 里的编译器,将讲解一些python的一些基础语法知识,是对上篇文章的补充,可以和我写的python数据分析——Python语言基础(数据结构基础)结合起来看,有些知识点可能在这篇文章写的不是很全面。
编程中的函数和数学中的函数有一定的相似之处.
数学上的函数 比如 y = sin x ,x 取不同的值 y就会得到不同的结果.
编程中的函数,是一段 可以被重复使用的代码片段 。
代码示例:求数列的和,不使用函数
sum =0
for i in range(1, 101):
sum+=i
print(sum)
sum=0
for i in range(300, 401):
sum += i
print(sum)
sum =0
for i in range(1, 1001):
sum += i
print(sum)
可以发现 这几组代码基本是相似的,只有一点点差异. 可以把重复代码提取出来, 做成一个函数基
实际开发中,复制粘贴是一种不太好的策略.实际开发的重复代码可能存在几十份甚至上百份.
一旦这个重复代码需要被修改,那就得改几十次,非常不便于维护.并且
# 正义一个水和困数
def calcSum(beg, end):
theSum = 0
for i in range(beg, end + 1):
theSum += i
print (theSum)
# 调用函数
# 求 1-100 的和
calcSum(1, 100)
# 求 300-400 的和
calcSum(300, 400)
# 求 1-1000 的和
calcSum(1, 1000)
创建函数/定义函数
def 函数名(形参列表):
函数体
return 返回值
调用函数/使用函数
函数名(实参列表) //不考虑返回值
返回值 = 函数名(实参列表) //考虑返回值
def test1():
print ('hello')
#如果光是定义函数,而不调用,则不会执行。
test3()
#还没有执行到定义,就先执行调用了,此时就会报错
def test3():
print ('hello')
在函数定义的时候,可以在()中指定"形式参数" (简称 形参),然后在调用的时候,由调用者把 “实际参数” (简称 实参) 传递进去.
这样就可以做到一份函数 针对不同的数据进行计算处理.
考虑前面的代码案例:
def calcSum(beg, end):
sum =0
for i in range(beg, end + 1):
sum += i
print (sum)
calcSum(1, 100)
calcSum(300, 400)
calcSum(1, 1000)
上面的代码中,beg,end 就是函数的形参.1,100 或 300,400 就是函数的实参.
函数的参数可以视为是函数的"输入",则函数的返回值, 就可以视为是函数的"输出".此处的"输入",“输出” 是更广义的输入输出,不是单纯指通过控制台输入输出.我们可以把函数想象成一个"工厂".工厂需要买入原材料, 进行加工, 并生产出产品.函数的参数就是原材料,函数的返回值就是生产出的产品.
下列代码
def calcSum(beg, end):
sum = 0
for i in range(beg, end + 1):
sum += i
print(sum)
calcSum(1,100)
可以转换成
def calcSum(beg, end):
sum = 0
for i in range(beg, end + 1):
sum += i
return sum
result = calcSum(1, 100)
print(result)
这两个代码的区别就在于,前者直接在函数内部进行了打印,后者则使用return语句把结果返回给函数调用者,再由调用者负责打印.
我们一般倾向于第二种写法.
实际开发中我们的一个通常的编程原则,是"逻辑和用户交互分离".
而第一种写法的函数中,既包含了计算逻辑,又包含了和用户交互(打印到控制台上),这种写法是不太好的,如果后续我们需要的是把计算结果保存到文件中,或者通过网络发送,或者展示到图形化界面里,那么第一种写法的函数,就难以胜任了.
而第二种写法则专注于做计算逻辑,不负责和用户交互. 那么就很容易把这个逻辑搭配不同的用户交互代码,来实现不同的效果.
def isodd(num):
if num % 2 == 0:
return False
else:
return True
result = isodd(10)
print (result)
def isodd(num):
if num % 2 == 0:
return False
return True
result = isodd(10)
print (result)
如果 num 是偶数 则进入 if 之后, 就会触发 return False,也就不会继续执行 return True
def getPoint():
x= 10
y= 20
return x, y
a, b = getPoint()
def getPoint():
x=10
y = 20
return x, y
_, b = getPoint ()
观察以下代码
def getPoint():
x= 10
y=20
return x, y
x, y = getPoint ()
在这个代码中,函数内部存在 x, y, 函数外部也有 x, y.
但是这两组 x, y 不是相同的变量, 而只是恰好有一样的名字.
变量只能在所在的函数内部生效.
在函数 getPoint()内部定义的 x, y 只是在函数内部生效. 一旦出了函数的范围,这两个变量就不再生效了.
def getPoint():
y= 20
x= 10
return x, y
getPoint ()
print(x, y)
在不同的作用域中, 允许存在同名的变量,虽然名字相同,实际上是不同的变量.
x=20
def test():
x = 10
print(f'函数内部 x = {x}')
test()
print(f'函数外部 x = {x}')
if, else, while, for 这些关键字也会引入 “代码块”,但是这些代码块不会对变量的作用域产生影响
在上述语句代码块内部定义的变量,可以在外面被访问
调用函数才会执行函数体代码. 不调用则不会执行.
函数体执行结束(或者遇到 return 语句),则回到函数调用位置, 继续往下执行.
def test():
print("执行函数内部代码")
print("执行函数内部代码")
print("执行函数内部代码")
print("1111")
test ()
print("2222")
test ()
print("3333")
这个过程还可以使用PyCharm 自带的调试器来观察.
#判定是否是奇数
def isodd(num):
if num % 2 ==0:
return False
else:
return True
result = isodd(10)
print (result)
实际上也可以简化
print (isodd(10))
把一个函数的返回值,作为另一个函数的参数, 这种操作称为链式调用.
这是一种比较常见的写法.
函数内部还可以调用其他的函数,这个动作称为"嵌套调用".
def test():
print("执行函数内部代码")
print("执行函数内部代码")
print("执行函数内部代码")
test函数内部调用了print函数,这里就属于嵌套调用.
一个函数里面可以嵌套调用任意多个函数.
函数嵌套的过程是非常灵活的.调试器的左下角,能够看到函数之间的"调用栈"每一层这个调用关系就称为"函数的栈帧",每个函数的局部变量就在这个栈帧中体现的,调用栈里面描述了当前这个代码的函数之间调用关系是啥
递归是 嵌套调用 中的一种特殊情况,即一个函数嵌套调用自己
代码示例: 递归计算 5!
def factor(n):
if n == 1:
return 1
return n * factor(n-1)
result = factor(5)
print (result)
上述代码中, 就属于典型的递归操作. 在 factor 函数内部, 又调用了 factor 自身.
注意:递归代码务必要保证
- 存在递归结束条件. 比如 if n == 1 就是结束条件. 当 n 为1 的时候. 递归就结束了.
- 每次递归的时候,要保证函数的实参是逐渐逼近结束条件的.
如果上述条件不能满足,就会出现"无限递归".这是一种典型的代码错误.
def factor(n):
return n factor(n - 1)
result = factor(5)
print (result)
如前面所描述, 函数调用时会在函数调用栈中记录每一层函数调用的信息。
但是函数调用栈的空间不是无限大的. 如果调用层数太多, 就会超出栈的最大范围, 导致出现问题.
在Python中,函数参数可以设置默认值,也就是说在调用函数时,如果没有对该参数进行赋值,就会自动使用该参数的默认值。设置函数参数默认值的语法如下:
def func_name(param1=default_value1, param2=default_value2, ...):
# function body
例如:
def greet(name="World"):
print(f"Hello, {name}!")
greet() # 输出: Hello, World!
greet("Python") # 输出: Hello, Python!
在上面的例子中,我们定义了一个函数greet()
,它有一个参数name
,默认值为"World"
。如果我们调用函数时不传递任何参数,则会使用默认值打印"Hello, World!“。如果我们传递了一个参数,例如"Python"
,则会使用传递的参数打印"Hello, Python!”。
在 Python 中,函数的参数可以设置默认值。这些默认值在调用函数时可以被忽略,如果没有传入值,则使用默认值。设置默认值的语法格式为在函数定义时在参数名后加上等号和默认值。例如:
def greet(name='World'):
print(f'Hello, {name}!')
greet() # 输出:Hello, World!
greet('Alice') # 输出:Hello, Alice!
在上面的示例中,当 greet()
函数被调用时,由于没有传入任何参数,因此默认值 name='World'
被使用。当 greet('Alice')
被调用时,传入的参数 name
覆盖了默认值,因此输出为 Hello, Alice!
。
在c++中支持默认值,但是在Java中不支持默认值,在编程领域对默认值的问题还是存在争议的
Python中,关键字参数是一种让函数调用更加清晰、简单的方式。在使用关键字参数时,调用者可以通过指定参数名来明确赋值,而不必考虑参数的顺序。
下面是关键字参数的语法结构,示例代码如下:
def function_name(param1=default_value1, param2=default_value2, ..., paramN=default_valueN):
# 函数体
pass
# 调用函数时通过关键字参数指定参数值
result = function_name(param1=value1, param2=value2, ..., paramN=valueN)
在上面的语法结构中,param1、param2等表示函数的参数名,default_value1、default_value2等表示参数对应的默认值,即如果调用者没有指定参数值,则会使用默认值。
关键字参数的好处在于,即使函数有很多参数,调用者也可以清晰地指定每个参数的值,避免了参数顺序带来的混淆。同时,使用关键字参数还可以让函数更加灵活,因为可以只指定需要的参数,而不必指定所有参数。
不止于此,关键词参数还可以让程序员明显的知道你的参数要传给谁
关键字参数,一般也就是搭配默认参数来使用的一个函数,可以提供很多的参数,来实现对这个函数的内部功能做出一些调整设定,为了降低调用者的使用成本,就可以把大部分参数设定出默认值当调用者需要调整其中的一部分参数的时候,就可以搭配关键字参数来进行操作。
编程中,经常需要使用变量, 来保存/表示数据.
如果代码中需要表示的数据个数比较少,我们直接创建多个变量即可.
num1 =10
num2 = 20
num3 = 30
但是有的时候,代码中需要表示的数据特别多,甚至也不知道要表示多少个数据.这个时候,就需要用到列表.
列表是一种让程序猿在代码中批量表示/保存数据的方式
就像我们去超市买辣条, 如果就只是买一两根辣条, 那咱们直接拿着辣条就走了.但是如果一次买个十根八根的, 这个时候用手拿就不好拿, 超市老板就会给我们个袋子.这个袋子, 就相当于列表
元组和列表相比, 是非常相似的,只是列表中放哪些元素可以修改调整,元组中放的元素是创建元组的时候就设定好的, 不能修改调整.
列表就是买散装辣条, 装好了袋子之后, 随时可以把袋子打开, 再往里多加辣条或者拿出去一些辣条.
元组就是买包装辣条,厂家生产好了辣条之后,一包就是固定的这么多,不能变动了.
列表和元组就和C语言的数组差不多,在功能上都是差不多的,但是元组创建后并且存放元素后,就不可以修改了,只能把整个元组删掉,列表是创建后还能修改
创建列表主要有两种方式.[ ] 表示一个空的列表.
alist = []
alist = list()
print (type(alist))
alist = [1, 2, 3, 4]
print (alist)
可以存放不同类型的数据,在C语言中,创建一个整型数组,只能存放整型
alist = [1, 'hello', True]
print (alist)
因为 list 本身是 Python 中的内建函数 不宜再使用 list 作为变量名, 因此命名为 alist
alist = [1, 2, 3, 4]
print (alist [2])
注意:下标是从 0开始计数的,因此下标为 2,则对应着 3这个元素.,
alist[0] == 1 alist[1] == 2 以此类推
my_list = [1, 2, 3, 4, 5]
element = my_list[2]
element = 10
my_list[2] = element
完整代码如下:
my_list = [1, 2, 3, 4, 5]
element = my_list[2]
element = 10
my_list[2] = element
print(my_list)
输出结果:
a = [1 , 2 , 3 , 4 ]
a[100] = 0
print(a)
a = [1 , 2 , 3 ,4 ]
print(len(a))
len可以传字符串,列表,元组,字典,自定义的类…… =>动态类型
例如,一个长度为5的列表,最后一个元素的下标是4,而在最后一个元素的左侧第一个元素的下标是-1。因此,使用负数下标可以轻松地查找列表中的最后一个元素。
以下是一个示例代码,它演示了如何使用负数下标查找列表中的数据:
my_list = [1, 2, 3, 4, 5]
print(my_list[-1]) # 输出 5,即最后一个元素
print(my_list[-2]) # 输出 4,即倒数第二个元素
print(my_list[-3:]) # 输出 [3, 4, 5],即倒数三个元素的列表
需要注意的是,负数下标的范围应该在列表的边界内,否则会引发“IndexError”异常。在Python中,负数下标代表从列表的末尾开始向前数。例如,一个长度为5的列表,最后一个元素的下标是4,而在最后一个元素的左侧第一个元素的下标是-1。因此,使用负数下标可以轻松地查找列表中的最后一个元素。
通过下标操作是一次取出里面第一个元素.
通过切片,则是一次取出一组连续的元素, 相当于得到一个子列表
alist = [1, 2, 3, 4]
print (alist [1:3])
alist[1:3]
中的 1:3 表示的是 [1,3)这样的由下标构成的前闭后开区间.
也就是从下标为 1 的元素开始, 到下标为 3 的元素结束, 但是不包含下标为 3 的元素.
所以最终结果只有 2,3
切片操作中可以省略前后边界
alist = [1, 2, 3, 4]
print (alist [1:])#省略后边界,表示获取到列表末尾
print (alist[:-1])# 省略前边界,表示从列表开头获取
print (alist [:])# 省略两个边界,表示获取到整个列表.
切片操作是一个比较高效的操作,进行切片的时候,只是取出了原有列表中的一个部分,并不涉及到"数据的拷贝",也就说明他是比较快速的
Python的切片操作可以使用步长(step)来控制每个元素的间隔。步长默认为1,即每个元素都被取出。如果指定了步长,则取出的元素间隔为步长。步长可以是正数或负数,正数表示从左到右取元素,负数表示从右到左取元素。
下面是带有步长的切片操作的示例:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 取出所有元素
print(a[:]) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 指定步长为2,取出所有奇数
print(a[::2]) # [1, 3, 5, 7, 9]
# 指定步长为2,取出所有偶数
print(a[1::2]) # [2, 4, 6, 8, 10]
# 反转元素顺序
print(a[::-1]) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
# 指定步长为-2,反转并取出所有奇数
print(a[::-2]) # [10, 8, 6, 4, 2]
# 指定步长为-2,反转并取出所有偶数
print(a[-2::-2]) # [9, 7, 5, 3, 1]
通过指定步长,可以灵活地取出想要的元素。
当切片范围超过有限下标的时候,不会出现异常!而是把符合的元素获取出来
“遍历” 指的是把元素一个一个的取出来, 再分别进行处理.
alist = [1, 2, 3, 4]
for elem in alist:
print(elem)
alist = [1, 2, 3, 4]
for i in range(0, len(alist)):
print (alist [i])
alist = [1, 2, 3, 4]
i= 0
while i < len(alist):
print (alist [i])
i+= 1
alist = [1, 2, 3, 4]
alist.append('hello')
print (alist)
此处的 append是搭配列表对象a,来一起使用的,而不是作为一个独立的函数.type, print, input, len, 自定义函数…都是独立的函数
这种要搭配对象来使用的函数(function),也叫做 “方法”(method)
在python里对象被视为“变量”
insert 第一个参数表示要插入元素的下标.
alist = [1, 2, 3, 4]
alist.insert(1, 'hello')
print (alist)
PS: 什么是 “方法” (method)
方法其实就是函数.只不过函数是独立存在的,而方法往往要依附于某个"对象".
像上述代码 alist . append, append 就是依附于 alist, 相当于是 “针对 alist 这个列表, 进行尾插操作”.
alist = [1, 2, 3, 4]
print(2 in alist)
print(10 in alist)
alist = [1, 2, 3, 4]
print (alist.index(2))
print (alist. index(10))
alist = [1, 2, 3, 4]
alist.pop()
print (alist)
alist = [1, 2, 3, 4]
alist.pop(2)
print (alist)
注意,如果要删除的值在列表中不存在,pop方法将会抛出ValueError异常。可以使用pop方法按下标删除列表中的元素。
my_list = [1, 2, 3, 4, 5]
my_list.remove(3)
print(my_list)
这将删除列表中第一个值为3的元素,即my_list变为[1, 2, 4, 5]。
注意,如果要删除的值在列表中不存在,remove方法将会抛出ValueError异常。可以使用remove方法按值删除列表中的元素。
此处的 + 结果会生成一个新的列表而不会影响到旧列表的内容.
alist = [1, 2, 3, 4]
blist = [5, 6, 7]
print(alist + blist)
我们也可以定义一个c来接收一下新列表,使用+号,原来的两个列表不变
a.extend(b),是把 b 中的内容拼接到 a 的末尾. 不会修改 b, 但是会修改 a.
alist = [1, 2, 3, 4]
blist = [5, 6, 7]
alist.extend(blist)
print(alist)
print (blist)
list1 = [1, 2, 3]
list2 = [4, 5, 6]
list1 += list2
print(list1) # 输出 [1, 2, 3, 4, 5, 6]
在上述示例中,list1 += list2
相当于 list1.extend(list2)
,即将list2
中的元素依次添加到list1
中。
元组的功能和列表相比, 基本是一致的.
元组使用()来表示.
atuple = ()
atuple = tuple()
在python里
None
表示什么都没有,表示为空,就和C语言里的NULL
差不多
元组不能修改里面的元素, 列表则可以修改里面的元素
因此,像读操作,比如访问下标,切片,遍历, in, index, + 等,元组也是一样支持的.
但是, 像写操作, 比如修改元素, 新增元素, 删除元素, extend 等, 元组则不能支持.
另外, 元组在 Python 中很多时候是默认的集合类型. 例如,当一个函数返回多个值的时候.
def getPoint():
return 10, 20
result = getPoint()
print (type(result))
此处的 result 的类型, 其实是元组.
问题来了,既然已经有了列表, 为啥还需要有元组?
元组相比于列表来说, 优势有两方面:
你有一个列表,现在需要调用一个函数进行一些处理,但是你有不是特别确认这个函数是否会把你的列表数据弄乱,那么这时候传一个元组就安全很多.
字典,是一个键值对结构.要求字典的键必须是"可hash对象"(字典本质上也是一个hash表).而一个可hash对象的前提就是不可变.因此元组的作用就体现了
可以通过索引来读取元组中的元素,
例如:
my_tuple = (1, 2, 3)
print(my_tuple[0]) # 输出 1
print(my_tuple[1]) # 输出 2
print(my_tuple[2]) # 输出 3
my_tuple = (1, 2, 3)
for item in my_tuple:
print(item)
my_tuple = (1, 2, 3)
print(my_tuple[0]) # 输出 1
print(my_tuple[1]) # 输出 2
print(my_tuple[2]) # 输出 3
例如,有一个元组my_tuple = (1, 2, 3, 4, 5)
,我们可以使用切片来获取第二个到第四个元素:
my_tuple[1:4] # 输出 (2, 3, 4)
切片的第一个索引是包含在结果中的,第二个索引是不包含在结果中的。如果省略第一个索引,则默认从开头开始切片,如果省略第二个索引,则默认切到末尾。
my_tuple[:3] # 输出 (1, 2, 3)
my_tuple[3:] # 输出 (4, 5)
my_tuple[-2:] # 输出 (4, 5)
连接操作将返回一个新的元组,其中包含连接的两个元组的所有元素。
下面是一个例子:
tuple1 = (1, 2, 3)
tuple2 = (4, 5, 6)
tuple3 = tuple1 + tuple2
print(tuple3) # 输出 (1, 2, 3, 4, 5, 6)
在上面的例子中,我们首先定义了两个元组 tuple1
和 tuple2
,然后使用加号运算符将它们连接起来,创建了一个新的元组 tuple3
。最后,我们打印出 tuple3
来查看连接的结果。
需要注意的是,元组是不可变的,这意味着我们不能直接修改一个元组的元素。因此,连接两个元组将创建一个新的元组,而不是在原始元组上进行修改。
同理,我们也可以使用根据列表的模板,进行数据的查找
字典是一种存储 键值对 的结构.
啥是键值对?
这是计算机/生活中一个非常广泛使用的概念.
把 键(key) 和 值(value) 进行一个一对一的映射,然后就可以根据键, 快速找到值.
举个例子,学校的每个同学,都会有一个唯一的学号.知道了学号,就能确定这个同学.此处"学号" 就是 “键”,这个"同学" 就是 “值”.,根据学号,可以快速找到这个学生
创建一个空的字典. 使用{ }表示字典.
a = { }
b = dict()
print (type(a))
print (type(b))
student = { 'id': 1, 'name': 'zhangsan' }
print (student)
student = {
'id': 1,
'name': 'zhangsan',}
print('id' in student)
print('score' in student)
也可以使用not in
只不过此处的 "下标"是 key.(可能是整数, 也可能是字符串等其他类型).
student = {'id': 1,
'name': 'zhangsan',}
print (student ['id'])
print (student ['name'])
对于字典来说,使用in或者[ ]来获取value,都是非常高效的操作!!
对于列表来说,使用in比较低效的,而使用[ ]是比较高效的,因为in 需要把整个列表都遍历一下
student = {
'id': 1,
'name': 'zhangsan',}
print(student ['score'])
在 Python 中,可以通过以下方式来新增和修改字典中的元素:
使用[ ]可以根据 key 来新增/修改 value.
student = {
'id': 1,
'name': 'zhangsan',
}
student['score'] = 90
print (student)
student = {
'id': 1,
'name': 'zhangsan',
'score': 80}
student['score'] = 90
print (student)
my_dict = {'name': 'Tom', 'age': 18}
# 通过赋值方式新增元素
my_dict['gender'] = 'Male'
# 通过 update() 方法批量新增元素
my_dict.update({'height': 180, 'weight': 70})
print(my_dict) # 输出:{'name': 'Tom', 'age': 18, 'gender': 'Male', 'height': 180, 'weight': 70}
my_dict = {'name': 'Tom', 'age': 18}
# 通过赋值方式修改元素
my_dict['age'] = 20
# 通过 update() 方法批量修改元素
my_dict.update({'name': 'Jack', 'gender': 'Male'})
print(my_dict) # 输出:{'name': 'Jack', 'age': 20, 'gender': 'Male'}
my_dict = {'name': 'Alice', 'age': 25, 'city': 'New York'}
# 删除键为'age'的元素
del my_dict['age']
# 打印字典
print(my_dict) # 输出:{'name': 'Alice', 'city': 'New York'}
# 清空整个字典
my_dict.clear()
# 打印字典
print(my_dict) # 输出:{}
在上面的示例中,我们使用del语句删除了字典中键为’age’的元素。
my_dict.pop(key, default)
其中,key是需要删除的元素的键;default是一个可选参数,表示如果要删除的元素不存在时返回的值。
例如,假设有一个字典my_dict,它包含以下元素:
my_dict = {'a': 1, 'b': 2, 'c': 3}
现在,如果要删除字典中的元素’b’,可以使用pop()方法:
my_dict.pop('b')
执行上述代码后,字典中的元素’b’将被删除,该方法也会返回被删除的元素的值 2。
如果要删除的元素不存在,可以设置默认值来避免出现KeyError异常。例如:
my_dict.pop('d', 'Not Found')
执行上述代码后,如果’d’不存在于字典中,将返回字符串’Not Found’。
student = {
'id': 1,
'name': 'zhangsan',
'score': 80}
for key in student:
print(key, student[key])
取出所有 key 和 value
student = {'id': 1,
'name': 'zhangsan',
'score': 80}
print (student.keys ())
此处 dict_keys 是一个特殊的类型, 专门用来表示字典的所有 key. 大部分元组支持的操作对于 dict_keys 同样适用.
my_dict
,可以使用以下代码取出所有的字典元素:for key, value in my_dict.items():
print(key, value)
这个代码块会遍历字典中的每一个键值对,并分别将键和值赋值给变量 key
和 value
,然后将它们输出。如果只需要取出所有的键,可以使用 my_dict.keys()
方法,如果只需要取出所有的值,可以使用 my_dict.values()
方法。
在C++或者Java中,哈希表里面的键值对存储的顺序,是无序的!
但是在 Python 中还不一样 Python 中做了特殊处理能够保证 遍历出来的顺序,就是和插入的顺序一致的!!
不是所有的类型都可以作为字典的 key.
字典本质上是一个 哈希表, 哈希表的 key 要求是 “可哈希的”, 也就是可以计算出一个哈希值.
print (hash(0))
print (hash(3.14))
print (hash('hello'))
print (hash(True))
print (hash(())) #()是一个空的元组
print(hash([1, 2, 3]))
print(hash({ 'id': 1 }))
字典,列表,元组Python中非常常用的内置类型
相比于 int, str, float…它们内部可以再包含其他元素了
他们像一个容器/集合类
Python中字典的合法key必须满足以下两个条件:
不可变性:key必须是不可变的数据类型,例如字符串、数字或元组等。
唯一性:key必须唯一,如果有重复的key,后面的key会覆盖前面的key。
关于哈希值
哈希值是将任意长度的消息(或数据)压缩成固定长度的唯一值的一个数值。哈希值也被称作散列值、指纹或摘要。通常情况下,哈希值的长度是固定的,比如MD5哈希算法的结果是128位二进制数,SHA-1哈希算法的结果是160位二进制数,SHA-256哈希算法的结果是256位二进制数。哈希值具有单向性、不可逆性和唯一性等特点,被广泛应用于密码学、数据完整性校验、数字签名等领域。