基础语法后,没意外就是进阶了吧 !?
啧啧啧,别急,还记得 Day1 参考了 backend roadmap 后所提出的七步骤吗?,今天我们要正式踏入第一步骤 - 资料结构,我已经听到你们的「蛤~~~到第三天了还在第一步骤 !?」,俗话说得好:「走得慢一点,踩得稳一点,重要的是走得远。」,人生不是短跑冲刺竞赛,或许你们和 RS 一样是社会新鲜人,或许有些社会历练,又或许你们已是社会老鸟,但至少你我都至少还期望自己会再战个几年吧 ?,就是这个 几年,有个几年的时间就够了,我们只是前面走得慢一点,了解得深一点,后来会省很多 Debug 的时间,到时候才知道谁走的快。
没有页码的目录
避免加上程式码会让文章冗长,所以先上目录,各位看官可以挑选自己有兴趣或不足的章节:
Python 的 资料结构listas Stackas QueuetupledictsetPython 的 资料结构
list
在 Python 的 list
和 Java、Kotlin 的 ArrayList
概念几乎一样,你可以把它们想成同一个结构,都是 有序、可变,可是要注意的是 list 里面装的资料,是不是可以容许 多种型别 在同一个 list ****?,在 Java 的世界,ArrayList 不能 装不同型别,这句话会有争议,因为聪明如你们的工程师们想出了各种解法,有兴趣可以参考 Create an ArrayList with multiple object types?;在 Kotlin 的世界,和 Java 一样也是 不能 装不同型别,依旧有各种解法,可以参考 Declaring List of multiple types in Kotlin;而 Python 的 list 是 可以 装下多种型别 的,所以在使用上必须特别注意,这也是 RS 为什么在 Day2,花这么多时间强调变数型别的原因。
以 RS 的使用经验来说,RS 建议让 list 只装同样型别的资料,在进行专案实作上,比较不会让自己和其他人搞混,减少出错的机会。而总是会有需要装下不同型别资料的时候,就可以使用接下来介绍的 tuple
,晚点再说,先来看看怎么用 list 吧。
# 先放入各种型别的变数 minteger = 10 mstring = "Hi, this is RS." mfloat = 3.14159 incremental_list = range(10) float_list = [8.787, -0.618, 3.14e+30] # 用 中括号[] 包起来, # 就是 python 宣告 list 的方法 # 再全部塞到一个混和型别的 list, # 除了用变数放入,也可以直接塞入值 # list 内也可以塞入另一个 list mix_type_list = [minteger, mstring, mfloat, incremental_list, float_list, "I bought a keychron k6, nice~"] # ############################### # 取用 list 内的资料的方式 # ############################### # 可直接看到 list 全部的资料 print(mix_type_list) # 输出为: [10, 'Hi, this is RS.', # 3.14159, range(0, 10), # [8.787, -0.618, 3.14e+30], # 'I bought a keychron k6, nice~'] # 可从前面数来的 index 取用 print(mix_type_list[1]) # 输出为 Hi, this is RS. # index 也可从后面数来 print(mix_type_list[-1]) # 输出为 I bought a keychron k6, nice~ # 取用 list 内的 list 的资料, # 可用 len(your_list) 来取得你的 list 长度 # list 不像阵列(Array)需要事先宣告大小 print(mix_type_list[len(mix_type_list)-2][0]) # 输出为 8.787
as Stack
在 Python 想要使用 Stack 不需要自己实作,直接使用 list 的 append
和 pop
操作即可。
# 因 list 内建 append(), pop() # 可以直接模拟出 stack 的效果 # Python 的 list 的最后一个逗号, # 可以写出来,也可以省略 list_as_stack = [0, 1, 2, 3, ] print(list_as_stack) # 输出为 [0, 1, 2, 3] # 在 list 的最后放入一个值 list_as_stack.append(4) print(list_as_stack) # 输出为 [0, 1, 2, 3, 4] # 从最后一项拿出 be_popped = list_as_stack.pop() print(list_as_stack) # 输出为 [0, 1, 2, 3] print(be_popped) # 输出为 4 # 值得注意的是,pop 可以传入 index 参数, # 这个 index 是从前面数过来的正顺序, # 而 pop() 的预设参数为 -1, # 也就是指向最后一个,使用时需要自行注意! # 如果要避免犯错,可以自己用 list.pop() # 实作出一个没有参数的 pop() function, # 强制只能 pop 最后一项
as Queue
在 Python 想使用 Queue 的话,你可以利用上面提到的 append
和 pop
来当作 queue,但是,官方文件有提到,这样的使用效率不好,原因是因为 list 的查找实作方式适合取用最后一项,有兴趣可以参考 Efficiency of using a Python list as a queue,想更了解的话,可以修演算法 (Algorithms) 的课程,通常都会教怎么去判断程式的执行效率。
官方建议,可以使用 deque
来解决效率问题,改用 popleft
,来取值。
# 依旧可以使用 list 的 append 和 pop # 来达到 queue 的效果,但效率不佳 # 量大 且 时常需要新增、取出的时候 # 效率问题将会更明显 list_as_queue = [0, 1, 2, 3] print(list_as_queue) # 输出为 [0, 1, 2, 3] # 与 stack 相同,是放到最后 list_as_queue.append(4) print(list_as_queue) # 输出为 [0, 1, 2, 3, 4] # 以 pop(0) 取出在 list 的第一项, # 在实作面是从最后一项走访到第一项 # 所以当你的 list size 越大,就越没效率 out_of_queue = list_as_queue.pop(0) print(list_as_queue) # 输出为 [1, 2, 3, 4] print(out_of_queue) # 输出为 0 # 使用 collections.deque # 将 list 转为 deque, # 再用 popleft(),取得第一项 from collections import deque effective_queue = deque(list_as_queue) print(effective_queue) # 输出为 deque([1, 2, 3, 4]) out_of_queue = effective_queue.popleft() print(effective_queue) # 输出为 deque([2, 3, 4]) print(out_of_queue) # 输出为 1
tuple
这个就是在楼上 list 有提到的 tuple
,RS 建议适合用在 混和型别 的情况,通常是你有一堆资料要传出去,要创一个 class 又太麻烦的时候,特别适合使用 tuple,tuple 还有一个特性是 不可变 (immutable),也就是说当你创立一个 tuple 后,如果要新增/删减,那么就需要重新再创一个,你不能修改它。
# tuple 可加小括号,也可不加, # 但有加小括号的话,是比较好阅读的 this_is_a_tuple = 10, 8.787, "哩贺" tuple_with_parentheses = ("我是 RS", 1.7878, 99) print(this_is_a_tuple) print(tuple_with_parentheses) # 还有一种情况是 RS 常用的, # 就是在输出一些很杂的资料的时候 import datetime print("嗨 RS,", "现在时间是", datetime.datetime.now(), ",\n本周天气是", ["晴天", "阴天", "晴天", "晴天", "晴天", "晴天", "晴天"]) # 输出为 嗨 RS, # 现在时间是 2020-02-05 19:28:15.395380 # 本周天气是 ['晴天', '阴天', '晴天', # '晴天', '晴天', '晴天', '晴天']
dict (Dictionary)
如果有用过 Java 或 Kotlin 的捧油们,可以把 dict
想成 HashMap
,都是 <key, value> 配对的形式,使用方法非常弹性,key 和 value 可以放入各种型别,目前 RS 试过的 key 有不能放 list 、set 和 dict,都是 unhashable,大家可以玩玩看,非常有趣,可是实际的使用情境上,还是尽量不要这么花式,不然连自己都不知道自己在写什么。关于 hashable 可以参考 What is the meaning of 'unhashable type' error in Python?
# dictionary 可以塞入的型别非常弹性dictionary = {2048: "好玩", 3.14159: ("这是", "pi", "拉"), "我是key": [1, 2, 3, 4, 5]}print(dictionary)# 输出为 {2048: '好玩', 3.14159: # ('这是', 'pi', '拉'), # '我是key': [1, 2, 3, 4, 5]}# 也可以额外新增一笔资料进去dictionary[8.787] = {"里面": "还可以包含另一个dict哦"}print(dictionary)# 输出为 {2048: '好玩', 3.14159: # ('这是', 'pi', '拉'), '我是key': # [1, 2, 3, 4, 5], 8.787: # {'里面': '还可以包含另一个dict哦'}}# 尝试更多 key 能接受的型别dictionary[("连key", "都可以是tuple")] = "太扯拉"print(dictionary)# 输出为 {2048: '好玩', 3.14159: # ('这是', 'pi', '拉'), '我是key': # [1, 2, 3, 4, 5], 8.787: # {'里面': '还可以包含另一个dict哦'}, # ('连key', '都可以是tuple'): '太扯拉'}
set
和 dictionary 一样,在 Java、Kotlin 中也有对应的结构 - HashMap
,而 set 的特性是 无排序、项目不重複,适合用在你有一些资料是不希望有重複值的时候,set 与 set 之间还有取交集(intersect
)、联集(union
)、差集(difference
)。
# set 和 dictionary 都是用大括号包起来, # 不要眼花看错啰,这时候命名就很重要了。 this_is_set = {9527, "你跟我重複就只会剩一个哦", "你跟我重複就只会剩一个哦", 9487, 2266, 9527} print(this_is_set) ''' 输出为 {'你跟我重複就只会剩一个哦', 2266, 9487, 9527} '''
最后,推荐大家阅读 (2018 12月) 轻鬆学习 Python:资料结构,里面提到很多以上资料结构的操作细节。
摄影师:Vladislav Vasnetsov,连结:Pexels
单日心得总结
其实 RS 在写文章的时候,都很纠结到底要举多少範例,每个结构的各种用法就已经足够写成一篇文章,希望各位看官们不要太鞭我的範例包含太少 QQ。
今天超开心能参加 好想工作室 的羽球团,趁这个机会认识到好多大神们,不然平常都是待在自己位置上敲键盘没机会聊天,开勋 <3。
这连续两天都在学习观念和语法,真的有点太无趣,明天就一起进入到 Django 的世界吧!
我是 RS,这是我的 不做怎么知道系列 文章,我们 明天见。
喜欢我的文章吗? 赶快来看看我都发了什么文章吧:我的文章目录
欢迎阅读我的上一篇: [不做怎么知道系列之Android开发者的30天后端养成故事 Day2] - 建立自信心 #一起练Python语法 #不能拖 #先照着教学做
欢迎阅读我的下一篇: [不做怎么知道系列之Android开发者的30天后端养成故事 Day4] - 动手做做看 #捲起袖子 #初探Django # DjangoHelloWorld