基础语法
前言
本文基于pycharm编译器,也可以使用Anaconda 里的编译器,将讲解一些python的一些基础语法知识,是对上篇文章的补充,可以和我写的python数据分析——Python语言基础(数据结构基础)结合起来看,有些知识点可能在这篇文章写的不是很全面。
一、函数
函数是什么
编程中的函数和数学中的函数有一定的相似之处.
数学上的函数 比如 y = sin x ,x 取不同的值 y就会得到不同的结果.
编程中的函数,是一段 可以被重复使用的代码片段 。
代码示例:求数列的和,不使用函数
- 求 1 -100 的和
sum =0 for i in range(1, 101): sum+=i print(sum)
- 求 300-400 的和
sum=0 for i in range(300, 401): sum += i print(sum)
- 求 1 -1000 的和
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 就是函数的实参.
- 在执行sum(1, 100)的时候,就相当于 beg = 1, end = 100,然后在函数内部就可以针对 1-100 进行运算.
- 在执行 sum(300, 400)的时候,就相当于 beg = 300, end = 400,然后在函数内部就可以针对 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语句把结果返回给函数调用者,再由调用者负责打印.
我们一般倾向于第二种写法.
实际开发中我们的一个通常的编程原则,是"逻辑和用户交互分离".
而第一种写法的函数中,既包含了计算逻辑,又包含了和用户交互(打印到控制台上),这种写法是不太好的,如果后续我们需要的是把计算结果保存到文件中,或者通过网络发送,或者展示到图形化界面里,那么第一种写法的函数,就难以胜任了.
而第二种写法则专注于做计算逻辑,不负责和用户交互. 那么就很容易把这个逻辑搭配不同的用户交互代码,来实现不同的效果.
- 一个函数中可以有多个 return 语句
判定是否是奇数
def isodd(num): if num % 2 == 0: return False else: return True result = isodd(10) print (result)
- 执行到 return 语句,函数就会立即执行结束,回到调用位置.
判定是否是奇数
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 自带的调试器来观察.
- 点击行号右侧的空白, 可以在代码中插入断点
- 右键, Debug, 可以按照调试模式执行代码. 每次执行到断点程序都会暂停下来.
- 使用
Step Into
(F7)功能可以逐行执行代码.
链式调用
#判定是否是奇数 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))
- 如果需要往里面设置初始值, 可以直接写在[ ] 当中.
可以直接使用 print 来打印 list 中的元素内容.
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)
- 可以使用内建函数len()获取元素个数
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]
通过指定步长,可以灵活地取出想要的元素。
当切片范围超过有限下标的时候,不会出现异常!而是把符合的元素获取出来
遍历列表元素
“遍历” 指的是把元素一个一个的取出来, 再分别进行处理.
- 最简单的办法就是使用 for 循环
alist = [1, 2, 3, 4] for elem in alist: print(elem)
- 也可以使用 for 按照范围生成下标, 按下标访问
alist = [1, 2, 3, 4] for i in range(0, len(alist)): print (alist [i])
- 还可以使用 while 循环. 手动控制下标的变化
alist = [1, 2, 3, 4] i= 0 while i < len(alist): print (alist [i]) i+= 1
新增元素
- 使用 append 方法, 向列表末尾插入一个元素(尾插).
alist = [1, 2, 3, 4] alist.append('hello') print (alist)
此处的 append是搭配列表对象a,来一起使用的,而不是作为一个独立的函数.type, print, input, len, 自定义函数…都是独立的函数
这种要搭配对象来使用的函数(function),也叫做 “方法”(method)
在python里对象被视为“变量”
- 使用 insert 方法,向任意位置插入一个元素
insert 第一个参数表示要插入元素的下标.
alist = [1, 2, 3, 4] alist.insert(1, 'hello') print (alist)
PS: 什么是 “方法” (method)
方法其实就是函数.只不过函数是独立存在的,而方法往往要依附于某个"对象".
像上述代码 alist . append, append 就是依附于 alist, 相当于是 “针对 alist 这个列表, 进行尾插操作”.
查找元素
- 使用 in 操作符,判定元素是否在列表中存在. 返回值是布尔类型.
alist = [1, 2, 3, 4] print(2 in alist) print(10 in alist)
- 使用 index 方法, 查找元素在列表中的下标. 返回值是一个整数. 如果元素不存在, 则会抛出异常.
alist = [1, 2, 3, 4] print (alist.index(2)) print (alist. index(10))
删除元素
- 使用 pop 方法删除最末尾元素
alist = [1, 2, 3, 4] alist.pop() print (alist)
- pop 也能按照下标来删除元素
alist = [1, 2, 3, 4] alist.pop(2) print (alist)
注意,如果要删除的值在列表中不存在,pop方法将会抛出ValueError异常。可以使用pop方法按下标删除列表中的元素。
- 使用remove方法,按照值删除元素.
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来接收一下新列表,使用+号,原来的两个列表不变
- 使用 extend 方法,相当于把一个列表拼接到另一个列表的后面.
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)
- 还可以使用负数索引来从后往前访问元素。
例如,-1表示最后一个元素,-2表示倒数第二个元素,以此类推。
my_tuple[-2:] # 输出 (4, 5)
- 在Python中,可以使用加号运算符(+)对元组进行连接。
连接操作将返回一个新的元组,其中包含连接的两个元组的所有元素。
下面是一个例子:
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))
- 也可以在创建的同时指定初始值
- 键值对之间使用,分割,键和值之间使用:分割.(冒号后面推荐加一个空格).
- 使用 print 来打印字典内容
student = { 'id': 1, 'name': 'zhangsan' } print (student)
- 为了代码更规范美观,在创建字典的时候往往会把多个键值对,分成多行来书写.
查找 key
- 使用 in 可以判定 key 是否在 字典 中存在. 返回布尔值.
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 需要把整个列表都遍历一下
- 如果 key 在字典中不存在, 则会抛出异常.
student = { 'id': 1, 'name': 'zhangsan',} print(student ['score'])
新增和修改元素
在 Python 中,可以通过以下方式来新增和修改字典中的元素:
使用[ ]可以根据 key 来新增/修改 value.
- 如果 key 不存在, 对取下标操作赋值, 即为新增键值对
student = { 'id': 1, 'name': 'zhangsan', } student['score'] = 90 print (student)
- 如果 key 已经存在, 对取下标操作赋值, 即为修改键值对的值.
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'}
删除元素
- 可以使用del语句来删除Python字典中的元素。
- 我们还可以使用clear()方法清空整个字典。
例如:
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’的元素。
- 使用pop()方法从字典中删除指定的元素。
该方法的语法如下:
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’。
遍历字典元素
- 直接使用 for 循环能够获取到字典中的所有的 key, 进一步的就可以取出每个值了.
student = { 'id': 1, 'name': 'zhangsan', 'score': 80} for key in student: print(key, student[key])
取出所有 key 和 value
- 使用 keys 方法可以获取到字典中的所有的 key
student = {'id': 1, 'name': 'zhangsan', 'score': 80} print (student.keys ())
此处 dict_keys 是一个特殊的类型, 专门用来表示字典的所有 key. 大部分元组支持的操作对于 dict_keys 同样适用.
- 使用 value 方法可以获取到字典中的所有的 key 和 value
假设有一个字典变量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.
字典本质上是一个 哈希表, 哈希表的 key 要求是 “可哈希的”, 也就是可以计算出一个哈希值.
- 可以使用 hash 函数计算某个对象的哈希值.
- 但凡能够计算出哈希值的类型,都可以作为字典的 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位二进制数。哈希值具有单向性、不可逆性和唯一性等特点,被广泛应用于密码学、数据完整性校验、数字签名等领域。